@js-toolkit/web-utils 1.58.0 → 1.59.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/FullscreenController.d.ts +3 -2
- package/FullscreenController.js +1 -1
- package/WakeLockController.d.ts +1 -0
- package/WakeLockController.js +1 -1
- package/getSecondsCounter.d.ts +1 -1
- package/getSecondsCounter.js +1 -1
- package/iframe/getAutoConnector.d.ts +1 -1
- package/iframe/getAutoConnector.js +1 -1
- package/media/MediaStreamController.d.ts +2 -2
- package/media/MediaStreamController.js +1 -1
- package/media/PipController.d.ts +3 -2
- package/media/PipController.js +1 -1
- package/media/TextTracksController/TextTracksController.d.ts +2 -2
- package/media/TextTracksController/TextTracksController.js +1 -1
- package/package.json +1 -1
- package/serviceWorker/ServiceWorkerInstaller.d.ts +3 -2
- package/serviceWorker/ServiceWorkerInstaller.js +1 -1
- package/viewableTracker.d.ts +1 -1
- package/viewableTracker.js +1 -1
- package/webrtc/PeerConnection.d.ts +3 -2
- package/webrtc/PeerConnection.js +1 -1
- package/ws/WSController.d.ts +2 -1
- package/ws/WSController.js +1 -1
- package/iframe/getAutoConnectClient.d.ts +0 -15
- package/iframe/getAutoConnectClient.js +0 -1
- package/iframe/getAutoConnectHost.d.ts +0 -21
- package/iframe/getAutoConnectHost.js +0 -1
- package/media/BaseMediaController.d.ts +0 -5
- package/media/BaseMediaController.js +0 -1
|
@@ -8,7 +8,7 @@ declare global {
|
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
export declare function enterPseudoFullscreen(element: Element & ElementCSSInlineStyle): VoidFunction;
|
|
11
|
-
export declare class FullscreenController extends EventEmitter<FullscreenController.EventMap> {
|
|
11
|
+
export declare class FullscreenController extends EventEmitter<FullscreenController.EventMap> implements AsyncDisposable {
|
|
12
12
|
private readonly element;
|
|
13
13
|
private options;
|
|
14
14
|
static isApiAvailable(): boolean;
|
|
@@ -18,7 +18,6 @@ export declare class FullscreenController extends EventEmitter<FullscreenControl
|
|
|
18
18
|
constructor(element: Element, options?: FullscreenController.Options);
|
|
19
19
|
private unbind;
|
|
20
20
|
setOptions(options: FullscreenController.Options): void;
|
|
21
|
-
destroy(): Promise<void>;
|
|
22
21
|
isAvailable(): boolean;
|
|
23
22
|
isFullscreen(): boolean;
|
|
24
23
|
isPseudoFullscreen(): boolean;
|
|
@@ -29,6 +28,8 @@ export declare class FullscreenController extends EventEmitter<FullscreenControl
|
|
|
29
28
|
private videoEndFullscreenHandler;
|
|
30
29
|
request(options?: FullscreenController.RequestOptions): Promise<void>;
|
|
31
30
|
exit(): Promise<void>;
|
|
31
|
+
destroy(): Promise<void>;
|
|
32
|
+
[Symbol.asyncDispose](): PromiseLike<void>;
|
|
32
33
|
}
|
|
33
34
|
export declare namespace FullscreenController {
|
|
34
35
|
type FullscreenType = 'video' | 'pseudo' | 'native';
|
package/FullscreenController.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{EventEmitter}from"eventemitter3";import{hasIn}from"@js-toolkit/utils/hasIn";import{fullscreen}from"./fullscreen";import{toggleNativeSubtitles}from"./media/toggleNativeSubtitles";export function enterPseudoFullscreen(e){let t,n;return t={position:e.style.position,left:e.style.left,top:e.style.top,width:e.style.width,height:e.style.height,maxWidth:e.style.maxWidth,maxHeight:e.style.maxHeight,zIndex:e.style.zIndex},n=e,n.style.position="fixed",n.style.left="0px",n.style.top="0px",n.style.width="100%",n.style.height="100%",n.style.maxWidth="100%",n.style.maxHeight="100%",n.style.zIndex="99999",()=>{t&&n&&(n.style.position=t.position,n.style.left=t.left,n.style.top=t.top,n.style.width=t.width,n.style.height=t.height,n.style.maxWidth=t.maxWidth,n.style.maxHeight=t.maxHeight,n.style.zIndex=t.zIndex),t=void 0,n=void 0}}export class FullscreenController extends EventEmitter{element;options;static isApiAvailable(){return fullscreen.isApiEnabled()}get Events(){return FullscreenController.Events}fallback;exitPseudoFullscreen;constructor(e,t={}){super(),this.element=e,this.options=t,this.setOptions(t)}unbind(){if(fullscreen.names){const{names:e}=fullscreen;this.element.removeEventListener(e.changeEventName,this.nativeChangeHandler),this.element.removeEventListener(e.errorEventName,this.nativeErrorHandler)}this.fallback instanceof HTMLVideoElement&&(this.fallback.removeEventListener("webkitbeginfullscreen",this.videoBeginFullscreenHandler),this.fallback.removeEventListener("webkitendfullscreen",this.videoEndFullscreenHandler),this.fallback=void 0)}setOptions(e){if(this.unbind(),this.options=e??{},this.fallback=this.options.fallback,fullscreen.names&&fullscreen.isApiEnabled()){const{names:e}=fullscreen;this.element.addEventListener(e.changeEventName,this.nativeChangeHandler),this.element.addEventListener(e.errorEventName,this.nativeErrorHandler)}else this.fallback instanceof HTMLVideoElement&&(this.fallback.addEventListener("webkitbeginfullscreen",this.videoBeginFullscreenHandler),this.fallback.addEventListener("webkitendfullscreen",this.videoEndFullscreenHandler))}
|
|
1
|
+
import{EventEmitter}from"eventemitter3";import{hasIn}from"@js-toolkit/utils/hasIn";import{fullscreen}from"./fullscreen";import{toggleNativeSubtitles}from"./media/toggleNativeSubtitles";export function enterPseudoFullscreen(e){let t,n;return t={position:e.style.position,left:e.style.left,top:e.style.top,width:e.style.width,height:e.style.height,maxWidth:e.style.maxWidth,maxHeight:e.style.maxHeight,zIndex:e.style.zIndex},n=e,n.style.position="fixed",n.style.left="0px",n.style.top="0px",n.style.width="100%",n.style.height="100%",n.style.maxWidth="100%",n.style.maxHeight="100%",n.style.zIndex="99999",()=>{t&&n&&(n.style.position=t.position,n.style.left=t.left,n.style.top=t.top,n.style.width=t.width,n.style.height=t.height,n.style.maxWidth=t.maxWidth,n.style.maxHeight=t.maxHeight,n.style.zIndex=t.zIndex),t=void 0,n=void 0}}export class FullscreenController extends EventEmitter{element;options;static isApiAvailable(){return fullscreen.isApiEnabled()}get Events(){return FullscreenController.Events}fallback;exitPseudoFullscreen;constructor(e,t={}){super(),this.element=e,this.options=t,this.setOptions(t)}unbind(){if(fullscreen.names){const{names:e}=fullscreen;this.element.removeEventListener(e.changeEventName,this.nativeChangeHandler),this.element.removeEventListener(e.errorEventName,this.nativeErrorHandler)}this.fallback instanceof HTMLVideoElement&&(this.fallback.removeEventListener("webkitbeginfullscreen",this.videoBeginFullscreenHandler),this.fallback.removeEventListener("webkitendfullscreen",this.videoEndFullscreenHandler),this.fallback=void 0)}setOptions(e){if(this.unbind(),this.options=e??{},this.fallback=this.options.fallback,fullscreen.names&&fullscreen.isApiEnabled()){const{names:e}=fullscreen;this.element.addEventListener(e.changeEventName,this.nativeChangeHandler),this.element.addEventListener(e.errorEventName,this.nativeErrorHandler)}else this.fallback instanceof HTMLVideoElement&&(this.fallback.addEventListener("webkitbeginfullscreen",this.videoBeginFullscreenHandler),this.fallback.addEventListener("webkitendfullscreen",this.videoEndFullscreenHandler))}isAvailable(){return fullscreen.isApiEnabled()||"pseudo"===this.fallback||this.fallback instanceof HTMLVideoElement&&!!this.fallback.webkitEnterFullscreen&&!!this.fallback.webkitSupportsFullscreen}isFullscreen(){return!!this.getCurrentElement()}isPseudoFullscreen(){return this.isFullscreen()&&!!this.exitPseudoFullscreen}getCurrentElement(){if(fullscreen.isApiEnabled()){if(fullscreen.getElement()===this.element)return this.element}else{if(this.exitPseudoFullscreen)return this.element;if(this.fallback instanceof HTMLVideoElement&&this.fallback.webkitDisplayingFullscreen)return this.fallback}return null}nativeChangeHandler=()=>{this.emit(this.Events.Change,{fullscreen:this.isFullscreen(),type:"native"})};nativeErrorHandler=e=>{this.emit(this.Events.Error,{error:e,type:"native"})};videoBeginFullscreenHandler=(()=>{const e=()=>{const t=this.fallback;e.controls=t.controls,e.nativeSubtitles=hasIn(this.options,"toggleNativeSubtitles")&&this.options.toggleNativeSubtitles&&t.textTracks.length>0,e.nativeSubtitles&&toggleNativeSubtitles(!0,t.textTracks),this.emit(this.Events.Change,{fullscreen:!0,type:"video"})};return e.nativeSubtitles=void 0,e.controls=void 0,e})();videoEndFullscreenHandler=()=>{const e=this.fallback;null!=this.videoBeginFullscreenHandler.controls&&(e.controls=this.videoBeginFullscreenHandler.controls),this.videoBeginFullscreenHandler.nativeSubtitles&&toggleNativeSubtitles(!1,e.textTracks),this.emit(this.Events.Change,{fullscreen:!1,type:"video"})};request(e={}){return new Promise(((t,n)=>{if(this.isFullscreen())return void t();if(fullscreen.isApiEnabled())return void fullscreen.request(this.element,e).then(t).catch(n);if("pseudo"===this.fallback)return this.exitPseudoFullscreen=enterPseudoFullscreen(this.element),this.emit(this.Events.Change,{fullscreen:!0,type:"pseudo"}),void t();const l=this.fallback instanceof HTMLVideoElement&&this.fallback||void 0;if(l?.webkitEnterFullscreen&&l.webkitSupportsFullscreen){const e=()=>{l.removeEventListener("webkitbeginfullscreen",e),t()};return l.addEventListener("webkitbeginfullscreen",e),void l.webkitEnterFullscreen()}n(new fullscreen.UnavailableError)}))}exit(){return new Promise(((e,t)=>{if(!this.isFullscreen())return void e();if(fullscreen.isApiEnabled())return void fullscreen.exit().then(e).catch(t);if(this.exitPseudoFullscreen)return this.exitPseudoFullscreen(),this.exitPseudoFullscreen=void 0,this.emit(this.Events.Change,{fullscreen:!1,type:"pseudo"}),void e();const n=this.fallback instanceof HTMLVideoElement&&this.fallback||void 0;if(n?.webkitExitFullscreen&&n.webkitSupportsFullscreen){const t=()=>{n.removeEventListener("webkitendfullscreen",t),e()};return n.addEventListener("webkitendfullscreen",t),void n.webkitExitFullscreen()}t(new fullscreen.UnavailableError)}))}destroy(){return this.exit().then((()=>new Promise((e=>{requestAnimationFrame((()=>{this.removeAllListeners(),this.unbind(),e()}))}))))}[Symbol.asyncDispose](){return this.destroy()}}!function(e){let t;!function(e){e.Change="change",e.Error="error"}(t=e.Events||(e.Events={}))}(FullscreenController||(FullscreenController={}));
|
package/WakeLockController.d.ts
CHANGED
package/WakeLockController.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DataEventEmitter}from"@js-toolkit/utils/DataEventEmitter";import{hasIn}from"@js-toolkit/utils/hasIn";export class WakeLockController extends DataEventEmitter{static isApiAvailable(){return hasIn(navigator,"wakeLock")&&null!=navigator.wakeLock}wakelock;releasing=!1;relockOnVisible=!1;restoreWakeLock=()=>{"visible"===document.visibilityState&&this.relockOnVisible&&(this.relockOnVisible=!1,this.request().catch((e=>this.emit("error",{error:e}))))};onRelease=()=>{this.wakelock&&(this.wakelock.removeEventListener("release",this.onRelease),this.wakelock=void 0,this.releasing?document.removeEventListener("visibilitychange",this.restoreWakeLock):"hidden"===document.visibilityState&&(this.relockOnVisible=!0,document.addEventListener("visibilitychange",this.restoreWakeLock)),this.emit("deactivated"))};isActive(){return!!this.wakelock&&!this.wakelock.released}async request(){if(!this.wakelock){try{this.wakelock=await navigator.wakeLock.request("screen")}catch(e){if("visible"===document.visibilityState)throw e;return this.relockOnVisible=!0,document.addEventListener("visibilitychange",this.restoreWakeLock),void this.emit("error",{error:e})}this.relockOnVisible=!1,this.wakelock.addEventListener("release",this.onRelease),this.emit("activated")}}async release(){if(this.wakelock&&!this.wakelock.released)try{this.releasing=!0,await this.wakelock.release(),this.relockOnVisible=!1}finally{this.releasing=!1}}async destroy(){await this.release(),this.removeAllListeners()}}
|
|
1
|
+
import{DataEventEmitter}from"@js-toolkit/utils/DataEventEmitter";import{hasIn}from"@js-toolkit/utils/hasIn";export class WakeLockController extends DataEventEmitter{static isApiAvailable(){return hasIn(navigator,"wakeLock")&&null!=navigator.wakeLock}wakelock;releasing=!1;relockOnVisible=!1;restoreWakeLock=()=>{"visible"===document.visibilityState&&this.relockOnVisible&&(this.relockOnVisible=!1,this.request().catch((e=>this.emit("error",{error:e}))))};onRelease=()=>{this.wakelock&&(this.wakelock.removeEventListener("release",this.onRelease),this.wakelock=void 0,this.releasing?document.removeEventListener("visibilitychange",this.restoreWakeLock):"hidden"===document.visibilityState&&(this.relockOnVisible=!0,document.addEventListener("visibilitychange",this.restoreWakeLock)),this.emit("deactivated"))};isActive(){return!!this.wakelock&&!this.wakelock.released}async request(){if(!this.wakelock){try{this.wakelock=await navigator.wakeLock.request("screen")}catch(e){if("visible"===document.visibilityState)throw e;return this.relockOnVisible=!0,document.addEventListener("visibilitychange",this.restoreWakeLock),void this.emit("error",{error:e})}this.relockOnVisible=!1,this.wakelock.addEventListener("release",this.onRelease),this.emit("activated")}}async release(){if(this.wakelock&&!this.wakelock.released)try{this.releasing=!0,await this.wakelock.release(),this.relockOnVisible=!1}finally{this.releasing=!1}}async destroy(){await this.release(),this.removeAllListeners()}[Symbol.asyncDispose](){return this.destroy()}}
|
package/getSecondsCounter.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface SecondsCounterOptions {
|
|
|
6
6
|
total: number;
|
|
7
7
|
}) => void) | undefined;
|
|
8
8
|
}
|
|
9
|
-
export interface SecondsCounter {
|
|
9
|
+
export interface SecondsCounter extends Disposable {
|
|
10
10
|
readonly getTotal: () => number;
|
|
11
11
|
readonly push: (currentTime: number | {
|
|
12
12
|
currentTime: number;
|
package/getSecondsCounter.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{toInt}from"@js-toolkit/utils/toInt";export function getSecondsCounter({onChange:t}={}){const e=new Set;let
|
|
1
|
+
import{toInt}from"@js-toolkit/utils/toInt";export function getSecondsCounter({onChange:t}={}){const e=new Set;let o=t,n=!1;return{getTotal:()=>e.size,push(t){if(n)throw new Error("SecondsCounter was destroyed.");const r="number"==typeof t?t:"currentTime"in t?t.currentTime:t.data.currentTime;if(null==t)return;const s=toInt(r);s>0&&!e.has(s)&&(e.add(s),o&&o({value:s,total:e.size}))},get onChange(){return o},set onChange(t){o=t},reset(){e.clear()},destroy(){n=!0,o=void 0,this.reset()},[Symbol.dispose](){this.destroy()}}}
|
|
@@ -4,7 +4,7 @@ export { getClientMessages, getHostMessages } from './messages';
|
|
|
4
4
|
interface StartOptions {
|
|
5
5
|
readonly append?: boolean;
|
|
6
6
|
}
|
|
7
|
-
interface AutoConnector {
|
|
7
|
+
interface AutoConnector extends Disposable {
|
|
8
8
|
/** If function passed the connector waits until DOM ready. */
|
|
9
9
|
readonly start: (targets: ArrayLike<Target> | (() => ArrayLike<Target>), options?: StartOptions) => void;
|
|
10
10
|
/** Stops a receiving new connections. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{v4 as uuid}from"uuid";import{onDOMReady}from"../onDOMReady";import{isPingMessage,isTargetReadyMessage}from"./messages";import{isWindowProxy,readTargets}from"./utils";import{getOriginFromMessage}from"./getOriginFromMessage";export{getClientMessages,getHostMessages}from"./messages";export function getAutoConnector({id:e,label:t,strictTargets:s=!0,messagesTypes:o,channel:n,logger:i=console,onSendData:a,onConnect:r}){const d=e||uuid(),g=t||d,c=new Map,u="open"===n?new Map:void 0;let f,p;const l=(e,t,s,o,n)=>{if(window!==t)if(isWindowProxy(t)){t.postMessage(e,s,n);const a=t===window.parent?"iframe parent":"iframe";i.debug(`${g}: Post message to ${a} (uid=${o},self.uid=${d},origin=${s}):`,e)}else t.postMessage(e,n&&{transfer:n}),i.debug(`${g}: Post message to MessageEventSource (uid=${o},self.uid=${d}):`,e)},m=(e,t,s)=>{l({uid:d,type:o.Ping},e,t,s)},h=e=>{if(!e.source||e.source===window)return;if(!isPingMessage(e.data,o)&&!isTargetReadyMessage(e.data,o))return;if(e.data.uid===d)return;const t=e.source,p=e.data.uid;if(i.debug(`${g}: Receive message from iframe (uid=${p},self.uid=${d},origin=${e.origin}):`,e.data),s&&f&&!f.has(t))return void i.debug(`${g}: Could not find target (uid=${p},self.uid=${d}) by message.source.`);const h=getOriginFromMessage(e);if(isPingMessage(e.data,o)&&!c.get(p)?.Ping)return c.set(p,{...c.get(p),Ping:!0}),void m(t,h,p);let w=!1;if(c.get(p)?.Ping&&!c.get(p)?.SelfReady){c.set(p,{...c.get(p),SelfReady:!0});const e={target:t,origin:h},s=u?(()=>{const t=u.get(p)?.[0]??new MessageChannel;return u.set(p,[t,e]),t.port2})():void 0;((e,t,s,n,i)=>{l({uid:d,type:o.SelfReady,data:e},t,s,n,i?[i]:void 0)})(a?a(e):void 0,t,h,p,s),w=!1}if(isTargetReadyMessage(e.data,o)&&c.get(p)?.SelfReady){c.delete(p),f?.delete(t);const s=(()=>{if("open"===n){const e=u?.get(p)?.[0].port1;if(!e)throw new Error("Something went wrong: MessageChannel is not created despite the fact that the `channel` option is `open`.");return e}if("use"===n){const t=e.ports[0];if(!t)throw new Error("MessagePort is not received despite the fact that the `channel` option is `use`. The `channel` option of connector on another side must be equals `open`.");return t}})(),{data:o}=e.data,a=()=>{i.debug(`${g}: Connection established (self.uid=${d} + uid=${p}).`),r({data:o,target:t,origin:h},s)};w?setTimeout(a,0):a()}},w=()=>{p&&(p(),p=void 0)};return{start:(e,t={})=>{if(p&&!t.append)return void i.warn(`${g}: Already started. You should first call \`stop\`.`);if(t.append){const e=f;w(),f=e}const s=()=>{const s=(()=>{const t="function"==typeof e?e():e;return t.length>0?t:void 0})(),o=s&&readTargets(s);if(!o)return;const n=new Set(o);t.append?(f||(f=new Set),n.forEach((e=>f.add(e)))):f=n,window.addEventListener("message",h);(t.append?n:f).forEach((e=>{e!==window&&m(e,"*","")}))},o="function"==typeof e?onDOMReady(s):s();p=()=>{o&&o(),window.removeEventListener("message",h),f=void 0}},stop:w,isStarted:()=>!!p,close:e=>{const t=e instanceof Set?e:new Set(readTargets(e));if(0!==t.size&&(u&&u.forEach((([e,s],o)=>{t.has(s.target)&&(e.port1.close(),e.port2.close(),u.delete(o))})),f)){const e=f;t.forEach((t=>e.delete(t)))}},destroy:()=>{w(),c.clear(),u&&(u.forEach((([e])=>{e.port1.close(),e.port2.close()})),u.clear())}}}
|
|
1
|
+
import{v4 as uuid}from"uuid";import{onDOMReady}from"../onDOMReady";import{isPingMessage,isTargetReadyMessage}from"./messages";import{isWindowProxy,readTargets}from"./utils";import{getOriginFromMessage}from"./getOriginFromMessage";export{getClientMessages,getHostMessages}from"./messages";export function getAutoConnector({id:e,label:t,strictTargets:s=!0,messagesTypes:o,channel:n,logger:i=console,onSendData:a,onConnect:r}){const d=e||uuid(),g=t||d,c=new Map,u="open"===n?new Map:void 0;let f,p;const l=(e,t,s,o,n)=>{if(window!==t)if(isWindowProxy(t)){t.postMessage(e,s,n);const a=t===window.parent?"iframe parent":"iframe";i.debug(`${g}: Post message to ${a} (uid=${o},self.uid=${d},origin=${s}):`,e)}else t.postMessage(e,n&&{transfer:n}),i.debug(`${g}: Post message to MessageEventSource (uid=${o},self.uid=${d}):`,e)},m=(e,t,s)=>{l({uid:d,type:o.Ping},e,t,s)},h=e=>{if(!e.source||e.source===window)return;if(!isPingMessage(e.data,o)&&!isTargetReadyMessage(e.data,o))return;if(e.data.uid===d)return;const t=e.source,p=e.data.uid;if(i.debug(`${g}: Receive message from iframe (uid=${p},self.uid=${d},origin=${e.origin}):`,e.data),s&&f&&!f.has(t))return void i.debug(`${g}: Could not find target (uid=${p},self.uid=${d}) by message.source.`);const h=getOriginFromMessage(e);if(isPingMessage(e.data,o)&&!c.get(p)?.Ping)return c.set(p,{...c.get(p),Ping:!0}),void m(t,h,p);let w=!1;if(c.get(p)?.Ping&&!c.get(p)?.SelfReady){c.set(p,{...c.get(p),SelfReady:!0});const e={target:t,origin:h},s=u?(()=>{const t=u.get(p)?.[0]??new MessageChannel;return u.set(p,[t,e]),t.port2})():void 0;((e,t,s,n,i)=>{l({uid:d,type:o.SelfReady,data:e},t,s,n,i?[i]:void 0)})(a?a(e):void 0,t,h,p,s),w=!1}if(isTargetReadyMessage(e.data,o)&&c.get(p)?.SelfReady){c.delete(p),f?.delete(t);const s=(()=>{if("open"===n){const e=u?.get(p)?.[0].port1;if(!e)throw new Error("Something went wrong: MessageChannel is not created despite the fact that the `channel` option is `open`.");return e}if("use"===n){const t=e.ports[0];if(!t)throw new Error("MessagePort is not received despite the fact that the `channel` option is `use`. The `channel` option of connector on another side must be equals `open`.");return t}})(),{data:o}=e.data,a=()=>{i.debug(`${g}: Connection established (self.uid=${d} + uid=${p}).`),r({data:o,target:t,origin:h},s)};w?setTimeout(a,0):a()}},w=()=>{p&&(p(),p=void 0)};return{start:(e,t={})=>{if(p&&!t.append)return void i.warn(`${g}: Already started. You should first call \`stop\`.`);if(t.append){const e=f;w(),f=e}const s=()=>{const s=(()=>{const t="function"==typeof e?e():e;return t.length>0?t:void 0})(),o=s&&readTargets(s);if(!o)return;const n=new Set(o);t.append?(f||(f=new Set),n.forEach((e=>f.add(e)))):f=n,window.addEventListener("message",h);(t.append?n:f).forEach((e=>{e!==window&&m(e,"*","")}))},o="function"==typeof e?onDOMReady(s):s();p=()=>{o&&o(),window.removeEventListener("message",h),f=void 0}},stop:w,isStarted:()=>!!p,close:e=>{const t=e instanceof Set?e:new Set(readTargets(e));if(0!==t.size&&(u&&u.forEach((([e,s],o)=>{t.has(s.target)&&(e.port1.close(),e.port2.close(),u.delete(o))})),f)){const e=f;t.forEach((t=>e.delete(t)))}},destroy:()=>{w(),c.clear(),u&&(u.forEach((([e])=>{e.port1.close(),e.port2.close()})),u.clear())},[Symbol.dispose](){this.destroy()}}}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import type { BaseMediaController } from './BaseMediaController';
|
|
2
1
|
export declare function attachMediaStream(media: HTMLMediaElement, stream: MediaStream | undefined): void;
|
|
3
2
|
export declare function removeTrack(mediaStream: MediaStream, track: MediaStreamTrack): void;
|
|
4
3
|
export declare function addTrack(mediaStream: MediaStream, track: MediaStreamTrack, onEnded?: VoidFunction): void;
|
|
5
|
-
export declare class MediaStreamController implements
|
|
4
|
+
export declare class MediaStreamController implements Disposable {
|
|
6
5
|
private mediaStream;
|
|
7
6
|
private media;
|
|
8
7
|
constructor(mediaStream: MediaStream);
|
|
@@ -13,4 +12,5 @@ export declare class MediaStreamController implements BaseMediaController {
|
|
|
13
12
|
addTrack(track: MediaStreamTrack, onEnded?: VoidFunction): void;
|
|
14
13
|
reset(): void;
|
|
15
14
|
destroy(): void;
|
|
15
|
+
[Symbol.dispose](): void;
|
|
16
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{resetMedia}from"./resetMedia";export function attachMediaStream(e,t){t&&t.active&&e.muted&&0===t.getVideoTracks().filter((e=>!e.getSettings().displaySurface)).length?e.srcObject=null:e.srcObject=t&&t.active?t:null}export function removeTrack(e,t){e.removeTrack(t),e.dispatchEvent(new MediaStreamTrackEvent("removetrack",{track:t}))}export function addTrack(e,t,a){e.addTrack(t),e.dispatchEvent(new MediaStreamTrackEvent("addtrack",{track:t})),t.addEventListener("ended",(()=>{removeTrack(e,t),a&&a()}),{once:!0})}export class MediaStreamController{mediaStream;media;constructor(e){this.mediaStream=e}attach(e){this.media=e,attachMediaStream(e,this.mediaStream)}detach(){if(this.media){const{media:e}=this;this.media=void 0,resetMedia(e)}}updateStream(e){if(this.mediaStream===e)return;const{media:t}=this;this.mediaStream=e,t&&this.attach(t)}removeTrack(e){removeTrack(this.mediaStream,e)}addTrack(e,t){addTrack(this.mediaStream,e,(()=>{this.removeTrack(e),t&&t()}))}reset(){this.mediaStream.getTracks().forEach((e=>{e.stop(),this.removeTrack(e)}))}destroy(){this.detach(),this.reset()}}
|
|
1
|
+
import{resetMedia}from"./resetMedia";export function attachMediaStream(e,t){t&&t.active&&e.muted&&0===t.getVideoTracks().filter((e=>!e.getSettings().displaySurface)).length?e.srcObject=null:e.srcObject=t&&t.active?t:null}export function removeTrack(e,t){e.removeTrack(t),e.dispatchEvent(new MediaStreamTrackEvent("removetrack",{track:t}))}export function addTrack(e,t,a){e.addTrack(t),e.dispatchEvent(new MediaStreamTrackEvent("addtrack",{track:t})),t.addEventListener("ended",(()=>{removeTrack(e,t),a&&a()}),{once:!0})}export class MediaStreamController{mediaStream;media;constructor(e){this.mediaStream=e}attach(e){this.media=e,attachMediaStream(e,this.mediaStream)}detach(){if(this.media){const{media:e}=this;this.media=void 0,resetMedia(e)}}updateStream(e){if(this.mediaStream===e)return;const{media:t}=this;this.mediaStream=e,t&&this.attach(t)}removeTrack(e){removeTrack(this.mediaStream,e)}addTrack(e,t){addTrack(this.mediaStream,e,(()=>{this.removeTrack(e),t&&t()}))}reset(){this.mediaStream.getTracks().forEach((e=>{e.stop(),this.removeTrack(e)}))}destroy(){this.detach(),this.reset()}[Symbol.dispose](){this.destroy()}}
|
package/media/PipController.d.ts
CHANGED
|
@@ -7,18 +7,19 @@ declare global {
|
|
|
7
7
|
webkitSetPresentationMode: (mode: VideoPresentationMode) => void;
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
|
-
export declare class PipController extends EventEmitter<PipController.EventMap> {
|
|
10
|
+
export declare class PipController extends EventEmitter<PipController.EventMap> implements AsyncDisposable {
|
|
11
11
|
private static isApiEnabled;
|
|
12
12
|
private static isWebkitApiEnabled;
|
|
13
13
|
static isAvailable(video: HTMLVideoElement): boolean;
|
|
14
14
|
get Events(): typeof PipController.Events;
|
|
15
15
|
private readonly listener;
|
|
16
16
|
constructor(video: HTMLVideoElement);
|
|
17
|
-
destroy(): Promise<void>;
|
|
18
17
|
isPip(): boolean;
|
|
19
18
|
getCurrentElement(): HTMLVideoElement | null;
|
|
20
19
|
request(): Promise<void>;
|
|
21
20
|
exit(): Promise<void>;
|
|
21
|
+
destroy(): Promise<void>;
|
|
22
|
+
[Symbol.asyncDispose](): PromiseLike<void>;
|
|
22
23
|
}
|
|
23
24
|
export declare namespace PipController {
|
|
24
25
|
enum Events {
|
package/media/PipController.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{EventEmitter}from"eventemitter3";import{EventEmitterListener}from"../EventEmitterListener";const getPipUnavailableError=()=>new Error("PiP is not available");export class PipController extends EventEmitter{static isApiEnabled(){return!!HTMLVideoElement.prototype.requestPictureInPicture&&!!document.exitPictureInPicture&&!!document.pictureInPictureEnabled}static isWebkitApiEnabled(e){return!!e.webkitSupportsPresentationMode&&e.webkitSupportsPresentationMode("picture-in-picture")}static isAvailable(e){return this.isApiEnabled()&&!e.disablePictureInPicture||this.isWebkitApiEnabled(e)}get Events(){return PipController.Events}listener;constructor(e){if(super(),this.listener=new EventEmitterListener(e),PipController.isAvailable(e)){const e=()=>{this.emit(this.Events.Change,{pip:!0})},t=()=>{this.emit(this.Events.Change,{pip:!1})};PipController.isApiEnabled()?(this.listener.on("enterpictureinpicture",e),this.listener.on("leavepictureinpicture",t)):this.listener.on("webkitpresentationmodechanged",(()=>{let i=this.listener.target.webkitPresentationMode;return()=>{"picture-in-picture"===this.listener.target.webkitPresentationMode?e():"picture-in-picture"===i&&t(),i=this.listener.target.webkitPresentationMode}})(),!0)}}
|
|
1
|
+
import{EventEmitter}from"eventemitter3";import{EventEmitterListener}from"../EventEmitterListener";const getPipUnavailableError=()=>new Error("PiP is not available");export class PipController extends EventEmitter{static isApiEnabled(){return!!HTMLVideoElement.prototype.requestPictureInPicture&&!!document.exitPictureInPicture&&!!document.pictureInPictureEnabled}static isWebkitApiEnabled(e){return!!e.webkitSupportsPresentationMode&&e.webkitSupportsPresentationMode("picture-in-picture")}static isAvailable(e){return this.isApiEnabled()&&!e.disablePictureInPicture||this.isWebkitApiEnabled(e)}get Events(){return PipController.Events}listener;constructor(e){if(super(),this.listener=new EventEmitterListener(e),PipController.isAvailable(e)){const e=()=>{this.emit(this.Events.Change,{pip:!0})},t=()=>{this.emit(this.Events.Change,{pip:!1})};PipController.isApiEnabled()?(this.listener.on("enterpictureinpicture",e),this.listener.on("leavepictureinpicture",t)):this.listener.on("webkitpresentationmodechanged",(()=>{let i=this.listener.target.webkitPresentationMode;return()=>{"picture-in-picture"===this.listener.target.webkitPresentationMode?e():"picture-in-picture"===i&&t(),i=this.listener.target.webkitPresentationMode}})(),!0)}}isPip(){return PipController.isApiEnabled()?document.pictureInPictureElement===this.listener.target:"picture-in-picture"===this.listener.target.webkitPresentationMode}getCurrentElement(){return this.isPip()?this.listener.target:null}request(){return new Promise(((e,t)=>{if(this.isPip())e();else{if(!PipController.isAvailable(this.listener.target))throw getPipUnavailableError();PipController.isApiEnabled()?this.listener.target.requestPictureInPicture().then((()=>e()),t):(this.listener.once("webkitpresentationmodechanged",(()=>{"picture-in-picture"===this.listener.target.webkitPresentationMode?e():t(new Error("Something went wrong."))}),!0),this.listener.target.webkitSetPresentationMode("picture-in-picture"))}}))}exit(){return new Promise(((e,t)=>{if(this.isPip()){if(!PipController.isAvailable(this.listener.target))throw getPipUnavailableError();PipController.isApiEnabled()?document.exitPictureInPicture().then(e,t):(this.listener.once("webkitpresentationmodechanged",(()=>{"picture-in-picture"!==this.listener.target.webkitPresentationMode?e():t(new Error("Something went wrong."))}),!0),this.listener.target.webkitSetPresentationMode("inline"))}else e()}))}destroy(){return this.exit().finally((()=>{this.removeAllListeners(),this.listener.removeAllListeners()}))}[Symbol.asyncDispose](){return this.destroy()}}!function(e){let t;!function(e){e.Change="change"}(t=e.Events||(e.Events={}))}(PipController||(PipController={}));
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { EventEmitter } from 'eventemitter3';
|
|
2
|
-
import type { BaseMediaController } from '../BaseMediaController';
|
|
3
2
|
import { type ActivateTextTrackInfo, type TextTrackInfo, type TextTrackItem } from './utils';
|
|
4
3
|
declare global {
|
|
5
4
|
interface HTMLMediaElementEventMap extends TextTracksEventMap {
|
|
@@ -14,7 +13,7 @@ export interface Cue extends PartialBut<OmitStrict<VTTCue, keyof EventTarget | '
|
|
|
14
13
|
readonly rows: string[];
|
|
15
14
|
}
|
|
16
15
|
export type { TextTrackInfo, ActivateTextTrackInfo, TextTrackItem };
|
|
17
|
-
export declare class TextTracksController extends EventEmitter<TextTracksController.EventMap> implements
|
|
16
|
+
export declare class TextTracksController extends EventEmitter<TextTracksController.EventMap> implements Disposable {
|
|
18
17
|
private readonly options;
|
|
19
18
|
private readonly eventListeners;
|
|
20
19
|
private addedTracks;
|
|
@@ -34,6 +33,7 @@ export declare class TextTracksController extends EventEmitter<TextTracksControl
|
|
|
34
33
|
getActiveTextTrack(): TextTrackInfo | undefined;
|
|
35
34
|
setActiveTextTrack(tt: ActivateTextTrackInfo | undefined): boolean;
|
|
36
35
|
destroy(): void;
|
|
36
|
+
[Symbol.dispose](): void;
|
|
37
37
|
}
|
|
38
38
|
export declare namespace TextTracksController {
|
|
39
39
|
interface Options {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{EventEmitter}from"eventemitter3";import{EventListeners}from"../../EventListeners";import{MediaNotAttachedError}from"../MediaNotAttachedError";import{parseTextTracks,setActiveTextTrack,addTextTracks,isIOSFullscreen,splitRows,buildCueId}from"./utils";function dispatchNativeEvent(t,e,
|
|
1
|
+
import{EventEmitter}from"eventemitter3";import{EventListeners}from"../../EventListeners";import{MediaNotAttachedError}from"../MediaNotAttachedError";import{parseTextTracks,setActiveTextTrack,addTextTracks,isIOSFullscreen,splitRows,buildCueId}from"./utils";function dispatchNativeEvent(t,e,s){t.dispatchEvent(new CustomEvent(e,{detail:s}))}export class TextTracksController extends EventEmitter{options;eventListeners=new EventListeners;addedTracks=[];textTrackList=[];media;textTrack;nextTextTrack;get Events(){return TextTracksController.Events}constructor(t){super(),this.options={emitNativeEvents:!1,hideActiveTrack:!0,preferCueRowLength:0},t&&this.setOptions(t)}setOptions(t){Object.assign(this.options,{...t,emitNativeEvents:t.emitNativeEvents??this.options.emitNativeEvents,hideActiveTrack:t.hideActiveTrack??this.options.hideActiveTrack,preferCueRowLength:t.preferCueRowLength??this.options.preferCueRowLength})}isAttached(){return!!this.media}getMediaElement(){if(!this.media)throw new MediaNotAttachedError;return this.media}detach(){this.eventListeners.removeAllListeners(),this.media=void 0,this.addedTracks=[],this.textTrackList=[],this.textTrack=void 0,this.nextTextTrack=void 0}attach(t){this.detach();const e=(()=>{const e=[];return s=>{const{activeCues:i}=s.target;if(!i)return;let a=e.length!==i.length;const r=new Array(i.length);for(let t=0;t<r.length;t+=1){const s=i[t];s.id=s.id||buildCueId(s,t),r[t]=s,r[t].rows=splitRows(s.text,this.options.preferCueRowLength),a||e[t]?.id===s.id||(a=!0),e[t]=s}e.length>r.length&&e.splice(r.length-e.length),a&&(this.emit(this.Events.TextTrackCueChanged,{textTrack:s.target,cues:r}),this.options.emitNativeEvents&&dispatchNativeEvent(t,"texttrackcuechange",{textTrack:s.target,cues:r}))}})(),s=()=>{this.textTrackList=parseTextTracks(t),this.emit(this.Events.TextTrackListChanged,{textTracks:this.textTrackList}),this.options.emitNativeEvents&&dispatchNativeEvent(t,"texttracklistchange",{textTracks:this.textTrackList}),setActiveTextTrack(t,this.textTrack??this.nextTextTrack,this.options.hideActiveTrack&&!isIOSFullscreen(t))};this.media=t,this.textTrackList=parseTextTracks(t);let i=!1;const a=t=>{i||s(),this.eventListeners.scope(t).on("cuechange",e)},r=t=>{s(),this.eventListeners.scope(t).off("cuechange",e)};if(this.eventListeners.scope(this.media.textTracks).on("change",(()=>{const{textTracks:e}=t,{nextTextTrack:s}=this;let i=-1;for(let a=0;a<e.length;a+=1){const r=e[a];if(r.language===s?.language&&r.kind===s?.kind||isIOSFullscreen(t)||(r.mode="disabled"),"disabled"!==r.mode&&i>=0&&(r.mode="disabled"),"disabled"!==r.mode){if(i=a,!r.native&&!isIOSFullscreen(t)){const t=this.options.hideActiveTrack?"hidden":"showing";r.mode!==t&&(r.mode=t)}r.native&&r.language===s?.language&&r.kind===s.kind&&(r.mode="showing")}}const a=e[i]&&(this.textTrackList[i]??{id:e[i].id,kind:e[i].kind,language:e[i].language,label:e[i].label});this.textTrack?.language===a?.language&&this.textTrack?.kind===a?.kind||(this.textTrack=a,this.nextTextTrack=this.textTrack,this.emit(this.Events.CurrentTextTrackChanged,{textTrack:this.textTrack,index:i}),this.options.emitNativeEvents&&dispatchNativeEvent(t,"texttrackchange",{textTrack:this.textTrack,index:i}))})).on("addtrack",(({track:t})=>t&&a(t))).on("removetrack",(({track:t})=>t&&r(t))),this.media.textTracks.length>0){i=!0;try{Array.prototype.forEach.call(this.media.textTracks,a),s()}finally{i=!1}}}getTextTracks(){return this.textTrackList}setTextTracks(t){const e=this.getMediaElement();if(this.eventListeners.scope(e,"@@setTextTracks").removeAllListeners(),this.addedTracks.forEach((t=>t.remove())),0===t.length)return;const s=()=>{addTextTracks(e,t,(t=>this.addedTracks.push(t))),this.textTrackList=parseTextTracks(e)};e.readyState>=e.HAVE_CURRENT_DATA?s():this.eventListeners.scope(e,"@@setTextTracks").once("loadeddata",s)}getActiveTextTrack(){return this.textTrack}setActiveTextTrack(t){const e=this.getMediaElement();return this.nextTextTrack=t&&this.textTrackList.find((e=>e.language===t.language&&(!t.kind||e.kind===t.kind))),setActiveTextTrack(e,this.nextTextTrack,this.options.hideActiveTrack&&!isIOSFullscreen(e))}destroy(){this.detach(),this.removeAllListeners()}[Symbol.dispose](){this.destroy()}}!function(t){let e;!function(t){t.TextTrackListChanged="TrackListChanged",t.CurrentTextTrackChanged="CurrentTextTrackChanged",t.TextTrackCueChanged="TextTrackCueChanged"}(e=t.Events||(t.Events={}))}(TextTracksController||(TextTracksController={}));
|
package/package.json
CHANGED
|
@@ -19,14 +19,15 @@ export declare class ServiceWorkerInstaller extends DataEventEmitter<{
|
|
|
19
19
|
error: [{
|
|
20
20
|
error: unknown;
|
|
21
21
|
}];
|
|
22
|
-
}, ServiceWorkerInstaller> {
|
|
22
|
+
}, ServiceWorkerInstaller> implements Disposable {
|
|
23
23
|
static isAvailable(): boolean;
|
|
24
24
|
private registration;
|
|
25
25
|
private cancelDefferedRegister;
|
|
26
26
|
constructor();
|
|
27
|
-
destroy(): void;
|
|
28
27
|
register(swUrl: string | URL, options?: ServiceWorkerInstaller.RegistrationOptions): void;
|
|
29
28
|
unregister(): void;
|
|
29
|
+
destroy(): void;
|
|
30
|
+
[Symbol.dispose](): void;
|
|
30
31
|
}
|
|
31
32
|
export declare namespace ServiceWorkerInstaller {
|
|
32
33
|
interface RegistrationOptions extends globalThis.RegistrationOptions {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DataEventEmitter}from"@js-toolkit/utils/DataEventEmitter";import{ErrorCompat}from"@js-toolkit/utils/ErrorCompat";import{onPageReady}from"../onPageReady";import{isLocalhost}from"./utils";export class ServiceWorkerUnavailableError extends ErrorCompat{constructor(){super(ServiceWorkerUnavailableError,"ServiceWorker is not available",{name:"ServiceWorkerUnavailableError"})}}export class ServiceWorkerInstaller extends DataEventEmitter{static isAvailable(){return"serviceWorker"in navigator}registration;cancelDefferedRegister;constructor(){super()}
|
|
1
|
+
import{DataEventEmitter}from"@js-toolkit/utils/DataEventEmitter";import{ErrorCompat}from"@js-toolkit/utils/ErrorCompat";import{onPageReady}from"../onPageReady";import{isLocalhost}from"./utils";export class ServiceWorkerUnavailableError extends ErrorCompat{constructor(){super(ServiceWorkerUnavailableError,"ServiceWorker is not available",{name:"ServiceWorkerUnavailableError"})}}export class ServiceWorkerInstaller extends DataEventEmitter{static isAvailable(){return"serviceWorker"in navigator}registration;cancelDefferedRegister;constructor(){super()}register(r,e){if(!ServiceWorkerInstaller.isAvailable())throw new ServiceWorkerUnavailableError;const{deffered:t,...i}=e??{},o=async()=>{try{if(isLocalhost()){const e=await fetch(r);if(!e.ok)throw new Error(`No service worker found at '${e.url}'.`,{cause:`Response: ${e.status} ${e.statusText}`})}const e=await navigator.serviceWorker.register(r,i);this.registration=e,this.emit("registered",{registration:e}),e.onupdatefound=()=>{const r=e.installing;null!=r&&(r.onstatechange=()=>{"installed"===r.state&&(navigator.serviceWorker.controller?this.emit("updatePending",{registration:e}):this.emit("updated",{registration:e}))},r.onerror=r=>{const e=new Error("Error during service worker installation",{cause:r});this.emit("error",{error:e})})}}catch(r){const e=new Error("Error during service worker registration",{cause:r});this.emit("error",{error:e})}};t?this.cancelDefferedRegister=onPageReady(o,"number"==typeof t?{timeout:t}:void 0):o()}unregister(){this.cancelDefferedRegister&&this.cancelDefferedRegister(),this.registration?.unregister().catch((r=>{const e=new Error("Error during service worker unregister",{cause:r});this.emit("error",{error:e})}))}destroy(){this.cancelDefferedRegister&&this.cancelDefferedRegister(),this.removeAllListeners()}[Symbol.dispose](){this.destroy()}}
|
package/viewableTracker.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export interface ViewableTrackerOptions {
|
|
|
5
5
|
readonly documentVisibility?: boolean | undefined;
|
|
6
6
|
readonly onChange: (viewable: boolean) => void;
|
|
7
7
|
}
|
|
8
|
-
export interface ViewableTracker {
|
|
8
|
+
export interface ViewableTracker extends Disposable {
|
|
9
9
|
readonly check: VoidFunction;
|
|
10
10
|
readonly destroy: VoidFunction;
|
|
11
11
|
}
|
package/viewableTracker.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import throttleFn from"lodash.throttle";export function getViewableTracker(t,{visiblePart:e=.8,scrollThrottle:i=200,documentVisibility:n=!0,onChange:o}){const
|
|
1
|
+
import throttleFn from"lodash.throttle";export function getViewableTracker(t,{visiblePart:e=.8,scrollThrottle:i=200,documentVisibility:n=!0,onChange:o}){const s=Math.min(+e,1);let r,l=0,c="visible"===document.visibilityState;const a=()=>{if(n&&"visible"!==document.visibilityState)return;const{top:e,bottom:i,height:l}=t.getBoundingClientRect(),c=l*s,a=e+c,d=window.innerHeight>=a&&i>c;r!==d&&(r=d,o(d))},d=()=>{const t="visible"===document.visibilityState;c!==t&&(c=t,t?(r=void 0,a()):r!==t&&o(t))},v=i&&i>0?throttleFn(a,i):()=>{n&&"visible"!==document.visibilityState||(l=window.requestAnimationFrame(a))};window.addEventListener("scroll",v,{capture:!1,passive:!0}),n&&document.addEventListener("visibilitychange",d);return{check:()=>{a(),n&&d()},destroy:()=>{cancelAnimationFrame(l),window.removeEventListener("scroll",v,{capture:!1}),document.removeEventListener("visibilitychange",d)},[Symbol.dispose](){this.destroy()}}}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { DataEventEmitter, type DataEventListener, type DataEventMap } from '@js-toolkit/utils/DataEventEmitter';
|
|
2
2
|
import * as sdpUtils from './sdputils';
|
|
3
|
-
export declare class PeerConnection extends DataEventEmitter<PeerConnection.EventMap, PeerConnection> {
|
|
3
|
+
export declare class PeerConnection extends DataEventEmitter<PeerConnection.EventMap, PeerConnection> implements Disposable {
|
|
4
4
|
readonly options: PeerConnection.Options;
|
|
5
5
|
get Events(): typeof PeerConnection.Events;
|
|
6
|
-
readonly logger: Pick<Console, "
|
|
6
|
+
readonly logger: Pick<Console, "warn" | "debug">;
|
|
7
7
|
private pc;
|
|
8
8
|
constructor(options?: PeerConnection.Options);
|
|
9
9
|
private clear;
|
|
@@ -31,6 +31,7 @@ export declare class PeerConnection extends DataEventEmitter<PeerConnection.Even
|
|
|
31
31
|
/** After calling this method the connection can no longer be used unless `reconnect` will be called. */
|
|
32
32
|
close(): void;
|
|
33
33
|
destroy(): void;
|
|
34
|
+
[Symbol.dispose](): void;
|
|
34
35
|
}
|
|
35
36
|
export declare namespace PeerConnection {
|
|
36
37
|
interface Options {
|
package/webrtc/PeerConnection.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DataEventEmitter}from"@js-toolkit/utils/DataEventEmitter";import{getErrorMessage}from"@js-toolkit/utils/getErrorMessage";import{hasIn}from"@js-toolkit/utils/hasIn";import*as sdpUtils from"./sdputils";export class PeerConnection extends DataEventEmitter{options;get Events(){return PeerConnection.Events}logger;pc;constructor(e={}){super(),this.options=e,this.logger=e.logger??console,this.pc=this.createPC()}clear(){this.pc.onsignalingstatechange=null,this.pc.onconnectionstatechange=null,this.pc.oniceconnectionstatechange=null,this.pc.ontrack=null,this.pc.onnegotiationneeded=null,this.pc.onicecandidate=null,this.pc.onicecandidateerror=null}createPC(){const e=new RTCPeerConnection(this.options.rtc);return e.onsignalingstatechange=()=>{this.logger.debug(`Signaling state changed to: ${e.signalingState}`),"closed"===e.signalingState&&(this.emit(this.Events.Closed),this.clear())},hasIn(RTCPeerConnection.prototype,"onconnectionstatechange")?e.onconnectionstatechange=()=>{this.logger.debug(`Connection state changed to: ${e.connectionState}`),"connected"===e.connectionState?this.emit(this.Events.Connected):"disconnected"===e.connectionState&&this.emit(this.Events.Disconnected)}:e.oniceconnectionstatechange=()=>{this.logger.debug(`ICE connection state changed to: ${e.iceConnectionState}`),"connected"===e.iceConnectionState?this.emit(this.Events.Connected):"disconnected"===e.iceConnectionState&&this.emit(this.Events.Disconnected)},e.ontrack=({streams:e,track:t})=>{if(this.logger.debug("Remote stream received.",e.length,t.kind),0===e.length)return;const[n]=e;n.onremovetrack=()=>{this.logger.debug("onremovetrack"),this.emit(this.Events.RemoteStreamChanged,n)},n.onaddtrack=()=>{this.logger.debug("onaddtrack"),this.emit(this.Events.RemoteStreamChanged,n)},this.emit(this.Events.RemoteStreamChanged,n)},e.onnegotiationneeded=()=>{const{iceConnectionState:t}=e;"connected"!==t&&"completed"!==t||(this.logger.debug("Reinitializing connection..."),this.emit(this.Events.ReinitializingConnectionRequired))},e.onicecandidate=({candidate:e})=>{e?sdpUtils.isValidIceCandidate(e)&&this.emit(this.Events.LocalIceCandidate,e):this.emit(this.Events.EndOfIceCandidates)},e.onicecandidateerror=e=>{if(e instanceof RTCPeerConnectionIceErrorEvent){const{errorCode:t,errorText:n,hostCandidate:i,url:o}=e;this.logger.warn(`ICE candidate error: errorCode=${t}, errorText=${n}, hostCandidate=${i}, url=${o}`)}else this.logger.warn(`ICE candidate error: ${getErrorMessage(e)}`)},e}async setLocalDescription(e,t){const n=sdpUtils.prepareLocalDescription(t,this.options.codecs);return await e.setLocalDescription(n),n}async setRemoteDescription(e,t){const n=sdpUtils.prepareRemoteDescription(t,this.options.codecs);return await e.setRemoteDescription(n),n}isConnected(){return"connected"===this.pc.iceConnectionState||"completed"===this.pc.iceConnectionState}isClosed(){return"closed"===this.pc.signalingState}addIceCandidate(e){return this.pc.addIceCandidate(e)}attachStream(e){const t=this.pc.getSenders(),n=t.length?e.getTracks().filter((e=>!t.find((({track:t})=>!!t&&t.id===e.id)))):e.getTracks();n.length?(n.forEach((t=>this.pc.addTrack(t,e))),this.logger.debug(`Attached ${n.length} track(s) to a peer connection.`)):this.logger.debug("No tracks to attach to a peer connection.")}reattachStream(e){const t=this.pc.iceConnectionState;if("new"!==t&&"connected"!==t&&"completed"!==t)return;const n=e?e.getTracks():[];this.pc.getSenders().forEach((e=>{const{track:t}=e;!t||"ended"!==t.readyState&&n.find((e=>e.id===t.id))||(this.pc.removeTrack(e),this.logger.debug(`'${t&&t.kind}' track is removed from a peer connection.`))})),e&&this.attachStream(e)}async createOffer(){const e=await this.pc.createOffer(this.options.offerOptions);return this.setLocalDescription(this.pc,e)}async createAnswer(e){await this.setRemoteDescription(this.pc,e);const t=await this.pc.createAnswer(this.options.offerOptions);return this.setLocalDescription(this.pc,t)}applyAnswer(e){return this.setRemoteDescription(this.pc,e)}reconnect(){this.close(),this.pc=this.createPC()}close(){this.pc.close(),this.pc.onsignalingstatechange&&(this.emit(this.Events.Closed),this.clear())}destroy(){this.close(),this.removeAllListeners()}}!function(e){let t;!function(e){e.LocalIceCandidate="LocalIceCandidate",e.EndOfIceCandidates="EndOfIceCandidates",e.Connected="Connected",e.Disconnected="Disconnected",e.RemoteStreamChanged="RemoteStreamChanged",e.ReinitializingConnectionRequired="ReinitializingConnectionRequired",e.Closed="Closed"}(t=e.Events||(e.Events={}))}(PeerConnection||(PeerConnection={}));
|
|
1
|
+
import{DataEventEmitter}from"@js-toolkit/utils/DataEventEmitter";import{getErrorMessage}from"@js-toolkit/utils/getErrorMessage";import{hasIn}from"@js-toolkit/utils/hasIn";import*as sdpUtils from"./sdputils";export class PeerConnection extends DataEventEmitter{options;get Events(){return PeerConnection.Events}logger;pc;constructor(e={}){super(),this.options=e,this.logger=e.logger??console,this.pc=this.createPC()}clear(){this.pc.onsignalingstatechange=null,this.pc.onconnectionstatechange=null,this.pc.oniceconnectionstatechange=null,this.pc.ontrack=null,this.pc.onnegotiationneeded=null,this.pc.onicecandidate=null,this.pc.onicecandidateerror=null}createPC(){const e=new RTCPeerConnection(this.options.rtc);return e.onsignalingstatechange=()=>{this.logger.debug(`Signaling state changed to: ${e.signalingState}`),"closed"===e.signalingState&&(this.emit(this.Events.Closed),this.clear())},hasIn(RTCPeerConnection.prototype,"onconnectionstatechange")?e.onconnectionstatechange=()=>{this.logger.debug(`Connection state changed to: ${e.connectionState}`),"connected"===e.connectionState?this.emit(this.Events.Connected):"disconnected"===e.connectionState&&this.emit(this.Events.Disconnected)}:e.oniceconnectionstatechange=()=>{this.logger.debug(`ICE connection state changed to: ${e.iceConnectionState}`),"connected"===e.iceConnectionState?this.emit(this.Events.Connected):"disconnected"===e.iceConnectionState&&this.emit(this.Events.Disconnected)},e.ontrack=({streams:e,track:t})=>{if(this.logger.debug("Remote stream received.",e.length,t.kind),0===e.length)return;const[n]=e;n.onremovetrack=()=>{this.logger.debug("onremovetrack"),this.emit(this.Events.RemoteStreamChanged,n)},n.onaddtrack=()=>{this.logger.debug("onaddtrack"),this.emit(this.Events.RemoteStreamChanged,n)},this.emit(this.Events.RemoteStreamChanged,n)},e.onnegotiationneeded=()=>{const{iceConnectionState:t}=e;"connected"!==t&&"completed"!==t||(this.logger.debug("Reinitializing connection..."),this.emit(this.Events.ReinitializingConnectionRequired))},e.onicecandidate=({candidate:e})=>{e?sdpUtils.isValidIceCandidate(e)&&this.emit(this.Events.LocalIceCandidate,e):this.emit(this.Events.EndOfIceCandidates)},e.onicecandidateerror=e=>{if(e instanceof RTCPeerConnectionIceErrorEvent){const{errorCode:t,errorText:n,hostCandidate:i,url:o}=e;this.logger.warn(`ICE candidate error: errorCode=${t}, errorText=${n}, hostCandidate=${i}, url=${o}`)}else this.logger.warn(`ICE candidate error: ${getErrorMessage(e)}`)},e}async setLocalDescription(e,t){const n=sdpUtils.prepareLocalDescription(t,this.options.codecs);return await e.setLocalDescription(n),n}async setRemoteDescription(e,t){const n=sdpUtils.prepareRemoteDescription(t,this.options.codecs);return await e.setRemoteDescription(n),n}isConnected(){return"connected"===this.pc.iceConnectionState||"completed"===this.pc.iceConnectionState}isClosed(){return"closed"===this.pc.signalingState}addIceCandidate(e){return this.pc.addIceCandidate(e)}attachStream(e){const t=this.pc.getSenders(),n=t.length?e.getTracks().filter((e=>!t.find((({track:t})=>!!t&&t.id===e.id)))):e.getTracks();n.length?(n.forEach((t=>this.pc.addTrack(t,e))),this.logger.debug(`Attached ${n.length} track(s) to a peer connection.`)):this.logger.debug("No tracks to attach to a peer connection.")}reattachStream(e){const t=this.pc.iceConnectionState;if("new"!==t&&"connected"!==t&&"completed"!==t)return;const n=e?e.getTracks():[];this.pc.getSenders().forEach((e=>{const{track:t}=e;!t||"ended"!==t.readyState&&n.find((e=>e.id===t.id))||(this.pc.removeTrack(e),this.logger.debug(`'${t&&t.kind}' track is removed from a peer connection.`))})),e&&this.attachStream(e)}async createOffer(){const e=await this.pc.createOffer(this.options.offerOptions);return this.setLocalDescription(this.pc,e)}async createAnswer(e){await this.setRemoteDescription(this.pc,e);const t=await this.pc.createAnswer(this.options.offerOptions);return this.setLocalDescription(this.pc,t)}applyAnswer(e){return this.setRemoteDescription(this.pc,e)}reconnect(){this.close(),this.pc=this.createPC()}close(){this.pc.close(),this.pc.onsignalingstatechange&&(this.emit(this.Events.Closed),this.clear())}destroy(){this.close(),this.removeAllListeners()}[Symbol.dispose](){this.destroy()}}!function(e){let t;!function(e){e.LocalIceCandidate="LocalIceCandidate",e.EndOfIceCandidates="EndOfIceCandidates",e.Connected="Connected",e.Disconnected="Disconnected",e.RemoteStreamChanged="RemoteStreamChanged",e.ReinitializingConnectionRequired="ReinitializingConnectionRequired",e.Closed="Closed"}(t=e.Events||(e.Events={}))}(PeerConnection||(PeerConnection={}));
|
package/ws/WSController.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ReconnectingWebSocket, { type ErrorEvent, type Message, type Options as BaseOptions, type UrlProvider } from 'reconnecting-websocket';
|
|
2
2
|
import { DataEventEmitter, type DataEventListener, type DataEventMap } from '@js-toolkit/utils/DataEventEmitter';
|
|
3
|
-
export declare class WSController<TData = unknown> extends DataEventEmitter<WSController.EventMap<TData>, WSController<TData>> {
|
|
3
|
+
export declare class WSController<TData = unknown> extends DataEventEmitter<WSController.EventMap<TData>, WSController<TData>> implements Disposable {
|
|
4
4
|
get Events(): typeof WSController.Events;
|
|
5
5
|
readonly logger: NonNullable<WSController.Options['logger']>;
|
|
6
6
|
protected readonly ws: ReconnectingWebSocket;
|
|
@@ -14,6 +14,7 @@ export declare class WSController<TData = unknown> extends DataEventEmitter<WSCo
|
|
|
14
14
|
send(data: Message): void;
|
|
15
15
|
close(code?: number, reason?: string): void;
|
|
16
16
|
destroy(): void;
|
|
17
|
+
[Symbol.dispose](): void;
|
|
17
18
|
}
|
|
18
19
|
export declare namespace WSController {
|
|
19
20
|
interface Options extends OptionalToUndefined<BaseOptions & Partial<Pick<WebSocket, 'binaryType'>>> {
|
package/ws/WSController.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import ReconnectingWebSocket,{}from"reconnecting-websocket";import{DataEventEmitter}from"@js-toolkit/utils/DataEventEmitter";import{delayed}from"@js-toolkit/utils/delayed";import{EventEmitterListener}from"../EventEmitterListener";function getNotConnectedError(){return new Error("The object is not connected yet.")}export class WSController extends DataEventEmitter{get Events(){return WSController.Events}logger;ws;listener;reconnectOnIdle;halfOpen;constructor(e,t){super();const{logger:n,protocols:s,binaryType:o,idleTimeout:r,halfOpenDetection:i,startClosed:c,...l}=t??{};this.logger=n??console,this.ws=new ReconnectingWebSocket(e,s,{...l,startClosed:!0}),null!=o&&(this.ws.binaryType=o),this.listener=new EventEmitterListener(this.ws),r&&r>0&&(this.reconnectOnIdle=delayed((()=>{this.logger.info(`WS connection reconnecting after ${r}ms due to inactivity.`),this.ws.reconnect()}),r)),this.halfOpen=(()=>{if(!i)return;const{pingTimeout:e=12e3,outMessage:t=()=>JSON.stringify({type:"pong"}),inMessageFilter:n=e=>e&&"object"==typeof e&&"ping"===e.type}=i,s=delayed((()=>{this.logger.info(`WS connection reconnecting after ${e}ms due to the probability of a half-open connection.`),this.ws.reconnect()}),e),o=()=>{s(),this.ws.send("function"!=typeof t||t instanceof Blob?t:t())};return{heartbeat:o,cancel:()=>s.cancel(),onMessage:({data:e})=>{n(e)?o():s()}}})(),this.listener.on("open",(()=>{this.reconnectOnIdle&&this.reconnectOnIdle(),this.halfOpen?.heartbeat(),this.emit(this.Events.Connected)})).on("close",(({code:e})=>{this.reconnectOnIdle?.cancel(),this.halfOpen?.cancel(),null!=t?.maxRetries&&this.ws.readyState===this.ws.CLOSED&&this.ws.retryCount===t.maxRetries&&this.close(e,`Failed to connect after ${t.maxRetries} attempts.`)})).on("message",(e=>{this.reconnectOnIdle&&this.reconnectOnIdle(),this.halfOpen?.onMessage(e),this.emit(this.Events.Message,e)})).on("error",(({error:e,message:t})=>{this.emit(this.Events.Error,{error:e,message:t})})),this.halfOpen&&(this.isConnected()||this.ws.readyState===this.ws.CONNECTING)&&this.halfOpen.heartbeat(),c||this.connect()}isConnected(){return this.ws.readyState===this.ws.OPEN}getUrl(){return this.ws.url}connect(){this.ws.reconnect()}send(e){if(!this.ws)throw getNotConnectedError();this.ws.send(e)}close(e,t){const n=!!this.ws;try{this.reconnectOnIdle&&this.reconnectOnIdle.cancel(),this.halfOpen&&this.halfOpen.cancel(),this.ws.close(e,t)}catch(e){this.logger.warn(e)}n&&this.emit(this.Events.Closed,t?{reason:t}:void 0)}destroy(){this.close(),this.listener.removeAllListeners(),this.removeAllListeners()}}!function(e){let t;!function(e){e.Connected="Connected",e.Message="Message",e.Error="Error",e.Closed="Closed"}(t=e.Events||(e.Events={}))}(WSController||(WSController={}));
|
|
1
|
+
import ReconnectingWebSocket,{}from"reconnecting-websocket";import{DataEventEmitter}from"@js-toolkit/utils/DataEventEmitter";import{delayed}from"@js-toolkit/utils/delayed";import{EventEmitterListener}from"../EventEmitterListener";function getNotConnectedError(){return new Error("The object is not connected yet.")}export class WSController extends DataEventEmitter{get Events(){return WSController.Events}logger;ws;listener;reconnectOnIdle;halfOpen;constructor(e,t){super();const{logger:n,protocols:s,binaryType:o,idleTimeout:r,halfOpenDetection:i,startClosed:c,...l}=t??{};this.logger=n??console,this.ws=new ReconnectingWebSocket(e,s,{...l,startClosed:!0}),null!=o&&(this.ws.binaryType=o),this.listener=new EventEmitterListener(this.ws),r&&r>0&&(this.reconnectOnIdle=delayed((()=>{this.logger.info(`WS connection reconnecting after ${r}ms due to inactivity.`),this.ws.reconnect()}),r)),this.halfOpen=(()=>{if(!i)return;const{pingTimeout:e=12e3,outMessage:t=()=>JSON.stringify({type:"pong"}),inMessageFilter:n=e=>e&&"object"==typeof e&&"ping"===e.type}=i,s=delayed((()=>{this.logger.info(`WS connection reconnecting after ${e}ms due to the probability of a half-open connection.`),this.ws.reconnect()}),e),o=()=>{s(),this.ws.send("function"!=typeof t||t instanceof Blob?t:t())};return{heartbeat:o,cancel:()=>s.cancel(),onMessage:({data:e})=>{n(e)?o():s()}}})(),this.listener.on("open",(()=>{this.reconnectOnIdle&&this.reconnectOnIdle(),this.halfOpen?.heartbeat(),this.emit(this.Events.Connected)})).on("close",(({code:e})=>{this.reconnectOnIdle?.cancel(),this.halfOpen?.cancel(),null!=t?.maxRetries&&this.ws.readyState===this.ws.CLOSED&&this.ws.retryCount===t.maxRetries&&this.close(e,`Failed to connect after ${t.maxRetries} attempts.`)})).on("message",(e=>{this.reconnectOnIdle&&this.reconnectOnIdle(),this.halfOpen?.onMessage(e),this.emit(this.Events.Message,e)})).on("error",(({error:e,message:t})=>{this.emit(this.Events.Error,{error:e,message:t})})),this.halfOpen&&(this.isConnected()||this.ws.readyState===this.ws.CONNECTING)&&this.halfOpen.heartbeat(),c||this.connect()}isConnected(){return this.ws.readyState===this.ws.OPEN}getUrl(){return this.ws.url}connect(){this.ws.reconnect()}send(e){if(!this.ws)throw getNotConnectedError();this.ws.send(e)}close(e,t){const n=!!this.ws;try{this.reconnectOnIdle&&this.reconnectOnIdle.cancel(),this.halfOpen&&this.halfOpen.cancel(),this.ws.close(e,t)}catch(e){this.logger.warn(e)}n&&this.emit(this.Events.Closed,t?{reason:t}:void 0)}destroy(){this.close(),this.listener.removeAllListeners(),this.removeAllListeners()}[Symbol.dispose](){this.destroy()}}!function(e){let t;!function(e){e.Connected="Connected",e.Message="Message",e.Error="Error",e.Closed="Closed"}(t=e.Events||(e.Events={}))}(WSController||(WSController={}));
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { type MessagesTypes } from './messages';
|
|
2
|
-
interface AutoConnectClient {
|
|
3
|
-
readonly ready: (origin?: string) => void;
|
|
4
|
-
readonly destroy: VoidFunction;
|
|
5
|
-
}
|
|
6
|
-
interface AutoConnectClientOptions<T = unknown> {
|
|
7
|
-
readonly data: T;
|
|
8
|
-
readonly target?: MessageEventSource | undefined;
|
|
9
|
-
readonly isReady?: () => boolean;
|
|
10
|
-
readonly onConnect: <T = unknown>(data: T, origin: string, port?: MessagePort) => void;
|
|
11
|
-
readonly logger?: Pick<Console, 'debug'> | undefined;
|
|
12
|
-
readonly messagesTypes?: Partial<MessagesTypes>;
|
|
13
|
-
}
|
|
14
|
-
export declare function getAutoConnectClient<T = unknown>({ data, target, isReady, onConnect, logger, messagesTypes: messagesTypes0, }: AutoConnectClientOptions<T>): AutoConnectClient;
|
|
15
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{v4 as uuid}from"uuid";import{IFRAME_CLIENT_READY,IFRAME_HOST_READY,IFRAME_PING,isPingMessage,isTargetReadyMessage}from"./messages";import{getOriginFromMessage}from"./getOriginFromMessage";import{isWindowProxy}from"./utils";export function getAutoConnectClient({data:e,target:s=window.parent,isReady:a=()=>!0,onConnect:t,logger:o=console,messagesTypes:i}){const n={Ping:i?.Ping||IFRAME_PING,TargetReady:i?.TargetReady||IFRAME_HOST_READY,SelfReady:i?.SelfReady||IFRAME_CLIENT_READY},r=uuid();let g;const d=(e,s,a)=>{window!==e&&(isWindowProxy(e)?(e.postMessage(s,a),o.debug(`Post message to parent window (origin=${a}):`,s)):(e.postMessage(s),o.debug("Post message to parent MessageEventSource:",s)))},u=i=>{if(!i.source||i.source!==s)return;if(!isPingMessage(i.data,n)&&!isTargetReadyMessage(i.data,n))return;o.debug(`Receive message from parent window (origin=${i.origin}):`,i.data);const u=getOriginFromMessage(i);if(isPingMessage(i.data,n))((e,s,t)=>{a()&&d(e,{uid:r,type:n.SelfReady,data:s},t)})(i.source,e,u);else{m();const{data:e}=i.data;[g]=i.ports,t(e,u,g),o.debug("Iframe connected.")}},m=()=>{window.removeEventListener("message",u)};return window.addEventListener("message",u),{ready:(e="*")=>{d(s,{uid:r,type:n.Ping},e)},destroy:()=>{m(),g&&(g.close(),g.onmessage=null,g.onmessageerror=null)}}}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { type MessagesTypes } from './messages';
|
|
2
|
-
interface AutoConnectHost {
|
|
3
|
-
readonly start: (...iframes: readonly HTMLIFrameElement[] | [() => readonly HTMLIFrameElement[]]) => void;
|
|
4
|
-
readonly stop: VoidFunction;
|
|
5
|
-
readonly destroy: VoidFunction;
|
|
6
|
-
/** Send `ready` to iframe. */
|
|
7
|
-
readonly ready: <T>(data: T, target: MessageEventSource, origin?: string) => void;
|
|
8
|
-
}
|
|
9
|
-
export type AutoConnectHostOptions<T = AnyObject> = {
|
|
10
|
-
readonly onSendData?: ((target: MessageEventSource, origin: string) => T) | undefined;
|
|
11
|
-
readonly logger?: Pick<Console, 'warn' | 'debug'> | undefined;
|
|
12
|
-
readonly messagesTypes?: Partial<MessagesTypes>;
|
|
13
|
-
} & ({
|
|
14
|
-
readonly openChannel: true;
|
|
15
|
-
readonly onConnect: <T = unknown>(data: T, target: MessageEventSource, origin: string, port: MessagePort) => void;
|
|
16
|
-
} | {
|
|
17
|
-
readonly openChannel?: false | undefined;
|
|
18
|
-
readonly onConnect: <T = unknown>(data: T, target: MessageEventSource, origin: string) => void;
|
|
19
|
-
});
|
|
20
|
-
export declare function getAutoConnectHost<T>({ onSendData, logger, openChannel, onConnect, messagesTypes: messagesTypes0, }: AutoConnectHostOptions<T>): AutoConnectHost;
|
|
21
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{v4 as uuid}from"uuid";import{onDOMReady}from"../onDOMReady";import{IFRAME_HOST_READY,IFRAME_CLIENT_READY,IFRAME_PING,isPingMessage,isTargetReadyMessage}from"./messages";import{isWindowProxy,selectFrames}from"./utils";import{getOriginFromMessage}from"./getOriginFromMessage";export function getAutoConnectHost({onSendData:e,logger:o=console,openChannel:s,onConnect:t,messagesTypes:n}){const r={Ping:n?.Ping||IFRAME_PING,TargetReady:n?.TargetReady||IFRAME_CLIENT_READY,SelfReady:n?.SelfReady||IFRAME_HOST_READY};let a,i;const d=uuid(),g=s?new MessageChannel:void 0,m=(e,s,t,n)=>{window!==s&&(isWindowProxy(s)?(s.postMessage(e,t,n),o.debug(`Post message to iframe (origin=${t}):`,e)):(s.postMessage(e,n&&{transfer:n}),o.debug("Post message to MessageEventSource:",e)))},u=(e,o)=>{m({uid:d,type:r.Ping},e,o)},c=(e,o,s="*")=>{m({uid:d,type:r.SelfReady,data:e},o,s,g?[g.port2]:void 0)},l=n=>{if(!n.source||n.source===window)return;if(!isPingMessage(n.data,r)&&!isTargetReadyMessage(n.data,r))return;o.debug(`Receive message from iframe (origin=${n.origin}):`,n.data);const a=n.source,i=getOriginFromMessage(n);if(isPingMessage(n.data,r))u(a,i);else{c(e?e(a,i):void 0,a,i);const{data:r}=n.data;setTimeout((()=>{s&&g?t(r,a,i,g.port1):s||t(r,a,i),o.debug("Iframe Host connected.")}),0)}},f=()=>{a&&(a(),a=void 0)};return{start:(...e)=>{if(a)return void o.warn("Already started. You should first call `stop`.");const s=onDOMReady((()=>{i=(()=>{const o="function"==typeof e[0]?e[0]():e;return o.length>0?o:void 0})();const o=i||selectFrames();window.addEventListener("message",l);for(let e=0;e<o.length;e+=1){const s=o[e];s.contentWindow&&u(s.contentWindow,"*")}}));a=()=>{s(),window.removeEventListener("message",l),i=void 0}},stop:f,ready:c,destroy:()=>{f(),g&&(g.port1.close(),g.port2.close(),g.port1.onmessage=null,g.port1.onmessageerror=null)}}}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export{};
|