@hopecloud/jetstream-player 1.1.5 → 1.3.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1 +1,76 @@
1
- Docs: https://jetstream-player.docs.hope.cloud/
1
+ # @hopecloud/jetstream-player
2
+
3
+ Control an embedded [Jetstream](https://jetstream-player.docs.hope.cloud/) player
4
+ from your page — play, pause, seek, mute, read playback state, and subscribe to
5
+ events — across the iframe boundary, with no server glue.
6
+
7
+ **[Full documentation →](https://jetstream-player.docs.hope.cloud/)**
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm i @hopecloud/jetstream-player
13
+ ```
14
+
15
+ ## Quick start
16
+
17
+ ```ts
18
+ import { JetstreamPlayer } from '@hopecloud/jetstream-player';
19
+
20
+ const player = new JetstreamPlayer('#player', {
21
+ mediaId: 'jsv:xxxxxxxxxx',
22
+ events: {
23
+ ready: () => console.log('ready'),
24
+ timeupdate: (time) => console.log('time', time),
25
+ },
26
+ });
27
+
28
+ player.play();
29
+ const muted = await player.isMuted();
30
+ ```
31
+
32
+ `mediaId` is the only required option; the library creates and mounts the iframe
33
+ at the given selector.
34
+
35
+ ## What you can do
36
+
37
+ - **Commands** — `play()`, `pause()`, `mute()`, `unmute()`, `seekTo(seconds)`,
38
+ `playNext()`, `playPrev()`.
39
+ - **Getters** (Promise-based) — `isMuted()`, `isPaused()`,
40
+ `getVideoCurrentTime()`, `getDuration()`. They reject after 5s if the player
41
+ doesn't reply.
42
+ - **Events** — subscribe via `options.events`: `ready`, `timeupdate`, `play`,
43
+ `pause`, `loadedmetadata`, `ended`, `volumechange`, `error`.
44
+ - **Teardown** — `dispose()` removes listeners and tears down Picture-in-Picture.
45
+
46
+ See the [options](https://jetstream-player.docs.hope.cloud/api/player-options)
47
+ and [methods](https://jetstream-player.docs.hope.cloud/api/player-methods)
48
+ reference for the full list.
49
+
50
+ ## Targeting a non-prod embed
51
+
52
+ By default the player loads the production embed. Point it at another host
53
+ (staging/dev) with `origin`:
54
+
55
+ ```ts
56
+ new JetstreamPlayer('#player', {
57
+ mediaId: 'jsv:xxxxxxxxxx',
58
+ origin: 'https://embed-stage.jetstream.studio',
59
+ });
60
+ ```
61
+
62
+ Communication is cross-origin `postMessage`, and the SDK learns the iframe's
63
+ real origin at runtime — so it keeps working even when the embed redirects.
64
+
65
+ ## Development
66
+
67
+ ```bash
68
+ pnpm install
69
+ pnpm build # rolldown + .d.ts
70
+ pnpm test # vitest
71
+ pnpm lint
72
+ pnpm typecheck
73
+ pnpm docs:dev # vitepress docs
74
+ ```
75
+
76
+ Architecture decisions are recorded in [`adr/`](./adr).
@@ -0,0 +1,7 @@
1
+ import type { EmbedFrameOptions } from './player.type';
2
+ export declare const buildEmbedSrc: (options: EmbedFrameOptions) => string;
3
+ export interface MountedFrame {
4
+ iframe: HTMLIFrameElement;
5
+ src: string;
6
+ }
7
+ export declare const mountEmbedFrame: (selector: string, options: EmbedFrameOptions) => MountedFrame;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  export { JetstreamPlayer } from './player';
2
2
  export * from './player.type';
3
- export * from './utils';
package/dist/index.js CHANGED
@@ -1,68 +1,43 @@
1
- //#region src/iframe-builder.ts
2
- var IFrameBuilder = class {
3
- options;
4
- iframe = null;
5
- constructor(options) {
6
- this.options = options;
7
- this.iframe = this.generateIframe();
8
- }
9
- generateIframe() {
10
- const iframe = document.createElement("iframe");
11
- iframe.allow = "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture";
12
- iframe.allowFullscreen = true;
13
- iframe.frameBorder = "0";
14
- iframe.title = "Jetstream player";
15
- iframe.src = this.options.src;
16
- iframe.width = this.options.width || "480px";
17
- iframe.height = this.options.height || "270px";
18
- iframe.classList.add("jet-stream-iframe-player");
19
- return iframe;
20
- }
21
- insertIframe(iframe) {
22
- const parent = document.querySelector(this.options.selector);
23
- if (parent) parent.appendChild(iframe);
24
- else console.error(`Element matching selector "${this.options.selector}" not found.`);
1
+ //#region src/embed-frame.ts
2
+ const DEFAULT_ORIGIN = "https://jstre.am";
3
+ const regionOrigin = (origin, region) => {
4
+ const url = new URL(origin);
5
+ if (region === "eu") {
6
+ const parts = url.hostname.split(".");
7
+ parts.splice(parts.length > 2 ? 1 : 0, 0, "eu");
8
+ url.hostname = parts.join(".");
25
9
  }
10
+ return url.origin;
26
11
  };
27
-
28
- //#endregion
29
- //#region src/iframe-builder-src.ts
30
- var IFrameBuilderSrc = class {
31
- options;
32
- origin = "https://jstre.am";
33
- constructor(options) {
34
- if (options.mediaId === "") throw new Error("mediaId not provided!");
35
- if (!options.mediaId.startsWith("jsv:")) throw new Error("mediaId must start with \"jsv:\"");
36
- if (typeof options.playerId !== "undefined") {
37
- if (options.playerId === "") throw new Error("playerId not provided!");
38
- if (!options.playerId.startsWith("jsp:")) throw new Error("playerId must start with \"jsp:\"");
39
- }
40
- this.options = options;
41
- }
42
- getRegionBasedOrigin() {
43
- const url = new URL(this.origin);
44
- const urlParts = url.hostname.split(".");
45
- if (this.options.region && this.options.region === "eu") if (urlParts.length > 2) urlParts.splice(1, 0, "eu");
46
- else urlParts.splice(0, 0, "eu");
47
- url.hostname = urlParts.join(".");
48
- return url.origin;
49
- }
50
- appendPath(path, builtUrl) {
51
- const pathString = String(path).trim();
52
- if (pathString.indexOf("/") === 0) builtUrl += pathString;
53
- else builtUrl += `/${pathString}`;
54
- return builtUrl;
55
- }
56
- buildSrc() {
57
- const url = new URL(`${this.getRegionBasedOrigin()}/embed/${this.options.mediaId}`);
58
- if (this.options.playerId) url.href = this.appendPath(this.options.playerId, url.href);
59
- if (this.options.region === "eu") url.searchParams.append("region", "eu");
60
- if (this.options.audioLang) url.searchParams.append("audioLang", this.options.audioLang.toLowerCase());
61
- if (this.options.subtitleLang) url.searchParams.append("subtitleLang", this.options.subtitleLang.toLowerCase());
62
- return url.href;
63
- }
12
+ const buildEmbedSrc = (options) => {
13
+ if (options.mediaId === "") throw new Error("mediaId not provided!");
14
+ const origin = regionOrigin(options.origin ?? DEFAULT_ORIGIN, options.region);
15
+ const path = options.playerId ? `/embed/${options.mediaId}/${options.playerId}` : `/embed/${options.mediaId}`;
16
+ const url = new URL(`${origin}${path}`);
17
+ if (options.region === "eu") url.searchParams.append("region", "eu");
18
+ if (options.audioLang) url.searchParams.append("audioLang", options.audioLang.toLowerCase());
19
+ if (options.subtitleLang) url.searchParams.append("subtitleLang", options.subtitleLang.toLowerCase());
20
+ return url.href;
21
+ };
22
+ const mountEmbedFrame = (selector, options) => {
23
+ const src = buildEmbedSrc(options);
24
+ const iframe = document.createElement("iframe");
25
+ iframe.allow = "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture";
26
+ iframe.allowFullscreen = true;
27
+ iframe.frameBorder = "0";
28
+ iframe.title = "Jetstream player";
29
+ iframe.src = src;
30
+ iframe.width = options.width || "480px";
31
+ iframe.height = options.height || "270px";
32
+ iframe.classList.add("jet-stream-iframe-player");
33
+ const parent = document.querySelector(selector);
34
+ if (parent) parent.appendChild(iframe);
35
+ else console.error(`Element matching selector "${selector}" not found.`);
36
+ return {
37
+ iframe,
38
+ src
39
+ };
64
40
  };
65
-
66
41
  //#endregion
67
42
  //#region src/iframe-pip-plugin.ts
68
43
  const PiP_STYLES = {
@@ -73,6 +48,8 @@ const PiP_STYLES = {
73
48
  height: "180px"
74
49
  };
75
50
  var IFramePiPPlugin = class {
51
+ containerSelector;
52
+ iframe;
76
53
  observer = null;
77
54
  originalParentHeight = null;
78
55
  originalIframeStyle = null;
@@ -125,142 +102,188 @@ var IFramePiPPlugin = class {
125
102
  this.destroy();
126
103
  }
127
104
  };
128
-
129
105
  //#endregion
130
- //#region src/utils.ts
131
- const normalizeEventData = (event) => {
132
- return JSON.parse(event.data);
133
- };
134
- const denormalizeEventData = (data) => {
135
- return JSON.stringify(data);
136
- };
137
- const isValidEventData = (rawData) => {
138
- if (typeof rawData !== "string") return false;
106
+ //#region src/protocol.ts
107
+ const encode = (command) => JSON.stringify(command);
108
+ const decode = (raw) => {
109
+ if (typeof raw !== "string") return null;
139
110
  try {
140
- JSON.parse(rawData);
141
- return true;
142
- } catch (error) {
143
- console.log("Error parsing JSON", error);
144
- return false;
111
+ const parsed = JSON.parse(raw);
112
+ if (typeof parsed === "object" && parsed !== null && typeof parsed.type === "string") return parsed;
113
+ return null;
114
+ } catch {
115
+ return null;
116
+ }
117
+ };
118
+ //#endregion
119
+ //#region src/player-bridge.ts
120
+ const REQUEST_TIMEOUT_MS = 5e3;
121
+ var PlayerBridge = class {
122
+ transport;
123
+ targetOrigin;
124
+ listeners = /* @__PURE__ */ new Set();
125
+ detach;
126
+ constructor(transport, initialTargetOrigin) {
127
+ this.transport = transport;
128
+ this.targetOrigin = initialTargetOrigin;
129
+ this.detach = this.transport.subscribe((message, origin) => {
130
+ const event = decode(message);
131
+ if (!event) return;
132
+ this.targetOrigin = origin;
133
+ this.listeners.forEach((listener) => listener(event));
134
+ });
135
+ }
136
+ send(command) {
137
+ this.transport.send(encode(command), this.targetOrigin);
138
+ }
139
+ subscribe(listener) {
140
+ this.listeners.add(listener);
141
+ return () => {
142
+ this.listeners.delete(listener);
143
+ };
144
+ }
145
+ request(command, timeoutMs = REQUEST_TIMEOUT_MS) {
146
+ return new Promise((resolve, reject) => {
147
+ let off = () => void 0;
148
+ const timer = setTimeout(() => {
149
+ off();
150
+ reject(/* @__PURE__ */ new Error(`Timed out waiting for "${command.name}" response`));
151
+ }, timeoutMs);
152
+ off = this.subscribe((event) => {
153
+ if (event.type === command.name) {
154
+ clearTimeout(timer);
155
+ off();
156
+ resolve(event.value);
157
+ }
158
+ });
159
+ this.send(command);
160
+ });
161
+ }
162
+ dispose() {
163
+ this.detach();
164
+ this.listeners.clear();
145
165
  }
146
166
  };
147
-
167
+ //#endregion
168
+ //#region src/player-transport.ts
169
+ const windowTransport = (iframe) => ({
170
+ send: (message, targetOrigin) => {
171
+ iframe.contentWindow?.postMessage(message, targetOrigin);
172
+ },
173
+ subscribe: (handler) => {
174
+ const listener = (event) => {
175
+ if (event.source !== iframe.contentWindow) return;
176
+ handler(event.data, event.origin);
177
+ };
178
+ window.addEventListener("message", listener);
179
+ return () => {
180
+ window.removeEventListener("message", listener);
181
+ };
182
+ }
183
+ });
148
184
  //#endregion
149
185
  //#region src/player.ts
150
186
  var JetstreamPlayer = class {
151
- iframe = null;
152
187
  options;
153
- registeredEvents = {};
188
+ listeners = /* @__PURE__ */ new Map();
154
189
  iFramePiP = null;
155
- targetOrigin = "*";
156
- boundSubscribeEventHandler;
190
+ bridge = null;
157
191
  constructor(el, options) {
158
192
  this.options = options;
159
- const src = new IFrameBuilderSrc({
160
- mediaId: options.mediaId,
161
- playerId: options.playerId,
162
- region: options.region
163
- }).buildSrc();
193
+ const { iframe, src } = mountEmbedFrame(el, options);
194
+ let initialTargetOrigin;
164
195
  try {
165
- this.targetOrigin = new URL(src).origin;
196
+ initialTargetOrigin = new URL(src).origin;
166
197
  } catch {
167
- this.targetOrigin = "*";
168
- }
169
- const iframeBuilder = new IFrameBuilder({
170
- selector: el,
171
- src,
172
- width: this.options.width,
173
- height: this.options.height
174
- });
175
- this.iframe = iframeBuilder.iframe;
176
- this.boundSubscribeEventHandler = this.subscribeEventHandler.bind(this);
177
- if (this.iframe) {
178
- iframeBuilder.insertIframe(this.iframe);
179
- this.iframe.addEventListener("load", () => {
180
- this.registerEvents();
181
- this.subscribeToRegisteredEvents();
182
- }, { once: true });
183
- if (typeof this.options.sticky !== "undefined" && this.options.sticky) this.iFramePiP = new IFramePiPPlugin(el, this.iframe);
198
+ initialTargetOrigin = "*";
184
199
  }
200
+ this.bridge = new PlayerBridge(windowTransport(iframe), initialTargetOrigin);
201
+ iframe.addEventListener("load", () => {
202
+ this.registerEvents();
203
+ this.bridge?.subscribe((event) => {
204
+ this.emit(event.type, event.value);
205
+ });
206
+ }, { once: true });
207
+ if (typeof this.options.sticky !== "undefined" && this.options.sticky) this.iFramePiP = new IFramePiPPlugin(el, iframe);
185
208
  }
186
209
  registerEvents() {
187
- if (!this.options.events || this.options.events && Object.keys(this.options.events).length === 0) return;
188
- Object.entries(this.options.events).forEach(([eventName, cb]) => {
189
- if (!(eventName in this.registeredEvents)) this.registeredEvents[eventName] = cb;
210
+ if (!this.options.events) return;
211
+ Object.entries(this.options.events).forEach(([eventName, handler]) => {
212
+ if (handler) this.on(eventName, handler);
190
213
  });
191
214
  }
192
- subscribeEventHandler(event) {
193
- if (!this.iframe?.contentWindow) return;
194
- if (event.source !== this.iframe.contentWindow) return;
195
- if (this.targetOrigin !== "*" && event.origin !== this.targetOrigin) return;
196
- if (!isValidEventData(event.data)) return;
197
- const data = normalizeEventData(event);
198
- const eventType = data.type;
199
- const handler = this.registeredEvents[eventType];
200
- if (handler) handler(data.value);
215
+ emit(type, value) {
216
+ const handlers = this.listeners.get(type);
217
+ if (!handlers) return;
218
+ [...handlers].forEach((handler) => handler(value));
201
219
  }
202
- subscribeToRegisteredEvents() {
203
- window.addEventListener("message", this.boundSubscribeEventHandler);
220
+ on(event, handler) {
221
+ let handlers = this.listeners.get(event);
222
+ if (!handlers) {
223
+ handlers = /* @__PURE__ */ new Set();
224
+ this.listeners.set(event, handlers);
225
+ }
226
+ handlers.add(handler);
227
+ return () => {
228
+ this.off(event, handler);
229
+ };
204
230
  }
205
- dispatch(event) {
206
- if (!this.iframe || !this.iframe.contentWindow) throw new Error("iframe is not provided or parent window not found!");
207
- this.iframe.contentWindow.postMessage(denormalizeEventData(event), this.targetOrigin);
231
+ off(event, handler) {
232
+ if (!handler) {
233
+ this.listeners.delete(event);
234
+ return;
235
+ }
236
+ const handlers = this.listeners.get(event);
237
+ if (!handlers) return;
238
+ handlers.delete(handler);
239
+ if (handlers.size === 0) this.listeners.delete(event);
208
240
  }
209
- getterDispatch(getterEvent) {
210
- return new Promise((resolve) => {
211
- this.dispatch(getterEvent);
212
- window.addEventListener("message", (event) => {
213
- if (event.source !== this.iframe?.contentWindow) return;
214
- if (this.targetOrigin !== "*" && event.origin !== this.targetOrigin) return;
215
- if (!isValidEventData(event.data)) return;
216
- const data = normalizeEventData(event);
217
- if (data.type === getterEvent.name) resolve(data.value);
218
- }, { once: true });
219
- });
241
+ request(command) {
242
+ if (!this.bridge) return Promise.reject(/* @__PURE__ */ new Error("iframe is not provided or parent window not found!"));
243
+ return this.bridge.request(command);
220
244
  }
221
245
  play() {
222
- this.dispatch({ name: "play" });
246
+ this.bridge?.send({ name: "play" });
223
247
  }
224
248
  pause() {
225
- this.dispatch({ name: "pause" });
249
+ this.bridge?.send({ name: "pause" });
226
250
  }
227
251
  mute() {
228
- this.dispatch({ name: "mute" });
252
+ this.bridge?.send({ name: "mute" });
229
253
  }
230
254
  unmute() {
231
- this.dispatch({ name: "unmute" });
255
+ this.bridge?.send({ name: "unmute" });
232
256
  }
233
257
  seekTo(seconds) {
234
- this.dispatch({
258
+ this.bridge?.send({
235
259
  name: "seekTo",
236
260
  params: seconds
237
261
  });
238
262
  }
239
263
  playNext() {
240
- this.dispatch({ name: "play-next" });
264
+ this.bridge?.send({ name: "play-next" });
241
265
  }
242
266
  playPrev() {
243
- this.dispatch({ name: "play-prev" });
267
+ this.bridge?.send({ name: "play-prev" });
244
268
  }
245
269
  isMuted() {
246
- return this.getterDispatch({ name: "is-muted" });
270
+ return this.request({ name: "is-muted" });
247
271
  }
248
272
  isPaused() {
249
- return this.getterDispatch({ name: "is-paused" });
273
+ return this.request({ name: "is-paused" });
250
274
  }
251
275
  getVideoCurrentTime() {
252
- return this.getterDispatch({ name: "get-video-current-time" });
276
+ return this.request({ name: "get-video-current-time" });
253
277
  }
254
278
  getDuration() {
255
- return this.getterDispatch({ name: "get-duration" });
279
+ return this.request({ name: "get-duration" });
256
280
  }
257
281
  dispose() {
258
- window.removeEventListener("message", this.boundSubscribeEventHandler);
259
- this.registeredEvents = {};
282
+ this.bridge?.dispose();
283
+ this.listeners.clear();
260
284
  this.iFramePiP?.destroy();
261
285
  }
262
286
  };
263
-
264
287
  //#endregion
265
288
  //#region src/player.type.ts
266
289
  const playerListenEvents = [
@@ -273,6 +296,5 @@ const playerListenEvents = [
273
296
  "volumechange",
274
297
  "error"
275
298
  ];
276
-
277
299
  //#endregion
278
- export { JetstreamPlayer, denormalizeEventData, isValidEventData, normalizeEventData, playerListenEvents };
300
+ export { JetstreamPlayer, playerListenEvents };
@@ -0,0 +1,13 @@
1
+ import type { PlayerCommand, PlayerEvent } from './player.type';
2
+ import type { PlayerTransport } from './player-transport';
3
+ export declare class PlayerBridge {
4
+ private readonly transport;
5
+ private targetOrigin;
6
+ private readonly listeners;
7
+ private readonly detach;
8
+ constructor(transport: PlayerTransport, initialTargetOrigin: string);
9
+ send(command: PlayerCommand): void;
10
+ subscribe(listener: (event: PlayerEvent) => void): () => void;
11
+ request<T>(command: PlayerCommand, timeoutMs?: number): Promise<T>;
12
+ dispose(): void;
13
+ }
@@ -0,0 +1,5 @@
1
+ export interface PlayerTransport {
2
+ send(message: string, targetOrigin: string): void;
3
+ subscribe(handler: (message: string, origin: string) => void): () => void;
4
+ }
5
+ export declare const windowTransport: (iframe: HTMLIFrameElement) => PlayerTransport;
package/dist/player.d.ts CHANGED
@@ -1,17 +1,15 @@
1
- import type { JetstreamPlayerOptions } from './player.type';
1
+ import type { PlayerEvents, JetstreamPlayerOptions, PlayerEventHandler } from './player.type';
2
2
  export declare class JetstreamPlayer {
3
- private iframe;
4
3
  private options;
5
- private registeredEvents;
4
+ private readonly listeners;
6
5
  private iFramePiP;
7
- private targetOrigin;
8
- private boundSubscribeEventHandler;
6
+ private bridge;
9
7
  constructor(el: string, options: JetstreamPlayerOptions);
10
8
  private registerEvents;
11
- private subscribeEventHandler;
12
- private subscribeToRegisteredEvents;
13
- private dispatch;
14
- private getterDispatch;
9
+ private emit;
10
+ on(event: PlayerEvents, handler: PlayerEventHandler): () => void;
11
+ off(event: PlayerEvents, handler?: PlayerEventHandler): void;
12
+ private request;
15
13
  play(): void;
16
14
  pause(): void;
17
15
  mute(): void;
@@ -5,25 +5,23 @@ export interface PlayerEvent {
5
5
  type: PlayerEvents | PlayerGetterEvents;
6
6
  value?: unknown;
7
7
  }
8
+ export type PlayerEventHandler = (value?: unknown) => void;
8
9
  export type PlayerCommandEvent = 'play' | 'pause' | 'mute' | 'unmute' | 'seekTo' | 'play-next' | 'play-prev';
9
10
  export interface PlayerCommand {
10
11
  name: PlayerCommandEvent | PlayerGetterEvents;
11
12
  params?: unknown;
12
13
  }
13
- export interface IFrameBuilderOpt {
14
- selector: string;
15
- src: string;
16
- width?: string;
17
- height?: string;
18
- }
19
- export interface IFrameBuilderSrcOpt {
14
+ export interface EmbedFrameOptions {
20
15
  mediaId: string;
21
16
  playerId?: string;
22
17
  region?: 'eu';
23
18
  audioLang?: string;
24
19
  subtitleLang?: string;
20
+ origin?: string;
21
+ width?: string;
22
+ height?: string;
25
23
  }
26
24
  export type JetstreamPlayerOptions = {
27
25
  sticky?: boolean;
28
- events?: Partial<Record<PlayerEvents, (value?: unknown) => void>>;
29
- } & Omit<IFrameBuilderOpt, 'selector' | 'src'> & IFrameBuilderSrcOpt;
26
+ events?: Partial<Record<PlayerEvents, PlayerEventHandler>>;
27
+ } & EmbedFrameOptions;
@@ -0,0 +1,3 @@
1
+ import type { PlayerCommand, PlayerEvent } from './player.type';
2
+ export declare const encode: (command: PlayerCommand) => string;
3
+ export declare const decode: (raw: string) => PlayerEvent | null;
package/package.json CHANGED
@@ -1,15 +1,25 @@
1
1
  {
2
2
  "name": "@hopecloud/jetstream-player",
3
- "version": "1.1.5",
3
+ "version": "1.3.0-rc.1",
4
4
  "description": "Jetstream Embed Player SDK",
5
5
  "type": "module",
6
+ "sideEffects": false,
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/hopechannel/hopecloud.git",
10
+ "directory": "libs/jetstream-player"
11
+ },
12
+ "homepage": "https://jetstream-player.docs.hope.cloud/",
13
+ "engines": {
14
+ "node": "24"
15
+ },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
6
19
  "main": "dist/index.js",
7
20
  "files": [
8
21
  "dist"
9
22
  ],
10
- "engines": {
11
- "node": "24"
12
- },
13
23
  "exports": {
14
24
  ".": {
15
25
  "types": "./dist/index.d.ts",
@@ -20,17 +30,14 @@
20
30
  "email": "code@deepvision.software",
21
31
  "name": "DV Software"
22
32
  },
23
- "repository": {
24
- "type": "git",
25
- "url": "https://github.com/hopechannel/jetstream-player"
26
- },
27
33
  "devDependencies": {
28
- "@deepvision/eslint-plugin": "2.0.0-rc.10",
29
- "@types/node": "^24.10.9",
34
+ "@deepvision/eslint-plugin": "2.0.3",
35
+ "@types/node": "24.12.0",
36
+ "eslint": "10.1.0",
30
37
  "happy-dom": "^20.4.0",
31
- "rolldown": "^1.0.0-beta.53",
32
- "typescript": "^5.9.3",
33
- "vitepress": "1.6.4",
38
+ "rolldown": "^1.1.4",
39
+ "typescript": "6.0.3",
40
+ "vitepress": "^1.6.4",
34
41
  "vitest": "^4.0.18"
35
42
  },
36
43
  "scripts": {
@@ -40,7 +47,7 @@
40
47
  "docs:preview": "vitepress preview docs",
41
48
  "lint": "eslint",
42
49
  "lint:fix": "eslint --fix",
43
- "typecheck": "tsc --noEmit",
50
+ "type-check": "tsc --noEmit",
44
51
  "test": "vitest",
45
52
  "test:run": "vitest run"
46
53
  }
@@ -1,9 +0,0 @@
1
- import { type IFrameBuilderSrcOpt } from './player.type';
2
- export declare class IFrameBuilderSrc {
3
- private options;
4
- origin: string;
5
- constructor(options: IFrameBuilderSrcOpt);
6
- getRegionBasedOrigin(): string;
7
- appendPath(path: string, builtUrl: string): string;
8
- buildSrc(): string;
9
- }
@@ -1,8 +0,0 @@
1
- import { type IFrameBuilderOpt } from './player.type';
2
- export declare class IFrameBuilder {
3
- options: IFrameBuilderOpt;
4
- iframe: HTMLIFrameElement | null;
5
- constructor(options: IFrameBuilderOpt);
6
- private generateIframe;
7
- insertIframe(iframe: HTMLIFrameElement): void;
8
- }
package/dist/utils.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export declare const normalizeEventData: <T = unknown>(event: MessageEvent<string>) => T;
2
- export declare const denormalizeEventData: <T = unknown>(data: T) => string;
3
- export declare const isValidEventData: (rawData: string) => boolean;