@js-toolkit/web-utils 1.59.1 → 1.60.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.
@@ -7,7 +7,6 @@ declare global {
7
7
  webkitSupportsFullscreen?: boolean | undefined;
8
8
  }
9
9
  }
10
- export declare function enterPseudoFullscreen(element: Element & ElementCSSInlineStyle): VoidFunction;
11
10
  export declare class FullscreenController extends EventEmitter<FullscreenController.EventMap> implements AsyncDisposable {
12
11
  private readonly element;
13
12
  private options;
@@ -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))}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={}));
1
+ import{EventEmitter}from"eventemitter3";import{hasIn}from"@js-toolkit/utils/hasIn";import{toggleNativeSubtitles}from"./media/toggleNativeSubtitles";import{fullscreen}from"./fullscreen";import{enterPseudoFullscreen}from"./fullscreenUtils";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/fullscreen.js CHANGED
@@ -1 +1 @@
1
- import{es5ErrorCompat}from"@js-toolkit/utils/es5ErrorCompat";import{promisify}from"@js-toolkit/utils/promisify";export class FullscreenUnavailableError extends Error{constructor(){super("Fullscreen is not available"),es5ErrorCompat(this,FullscreenUnavailableError)}}export var fullscreen;!function(e){e.names=[{requestFullscreenName:"requestFullscreen",exitFullscreenName:"exitFullscreen",fullscreenElementName:"fullscreenElement",fullscreenEnabledName:"fullscreenEnabled",changeEventName:"fullscreenchange",errorEventName:"fullscreenerror"},{requestFullscreenName:"webkitRequestFullscreen",exitFullscreenName:"webkitExitFullscreen",fullscreenElementName:"webkitFullscreenElement",fullscreenEnabledName:"webkitFullscreenEnabled",changeEventName:"webkitfullscreenchange",errorEventName:"webkitfullscreenerror"},{requestFullscreenName:"webkitRequestFullScreen",exitFullscreenName:"webkitCancelFullScreen",fullscreenElementName:"webkitCurrentFullScreenElement",fullscreenEnabledName:"webkitCancelFullScreen",changeEventName:"webkitfullscreenchange",errorEventName:"webkitfullscreenerror"},{requestFullscreenName:"mozRequestFullScreen",exitFullscreenName:"mozCancelFullScreen",fullscreenElementName:"mozFullScreenElement",fullscreenEnabledName:"mozFullScreenEnabled",changeEventName:"mozfullscreenchange",errorEventName:"mozfullscreenerror"},{requestFullscreenName:"msRequestFullscreen",exitFullscreenName:"msExitFullscreen",fullscreenElementName:"msFullscreenElement",fullscreenEnabledName:"msFullscreenEnabled",changeEventName:"MSFullscreenChange",errorEventName:"MSFullscreenError"}].find((({exitFullscreenName:e})=>e in document));const n={change:e.names?.changeEventName,error:e.names?.errorEventName};function r(){if(!e.names)throw new e.UnavailableError;return Boolean(document[e.names.fullscreenElementName])}function l(e,r,l){const t=n[e];t&&document.addEventListener(t,r,l)}function t(e,r,l){const t=n[e];t&&document.removeEventListener(t,r,l)}function a(n,r){return new Promise(((a,s)=>{if(!e.names)throw new e.UnavailableError;const c=()=>{t("change",c),t("error",u),a()},u=e=>{t("change",c),t("error",u),s(e)};l("change",c),l("error",u);const o=n[e.names.requestFullscreenName](r);o instanceof Promise&&o.then(c).catch(u)}))}function s(){return new Promise(((n,a)=>{if(!e.names)throw new e.UnavailableError;if(!r)return void n();const s=()=>{t("change",s),t("error",c),n()},c=e=>{t("change",s),t("error",c),a(e)};l("change",s),l("error",c);const u=document[e.names.exitFullscreenName]();u instanceof Promise&&u.then(s).catch(c)}))}e.UnavailableError=FullscreenUnavailableError,e.isApiAvailable=function(){return!!e.names},e.isApiEnabled=function(){return!!e.names&&Boolean(document[e.names.fullscreenEnabledName])},e.isFullscreen=r,e.getElement=function(){if(!e.names)throw new e.UnavailableError;return document[e.names.fullscreenElementName]},e.on=l,e.off=t,e.request=a,e.exit=s,e.toggle=function(e){return promisify((()=>r()?s():a(e)))},e.onChange=function(e){l("change",e)},e.onError=function(e){l("error",e)}}(fullscreen||(fullscreen={}));
1
+ import{es5ErrorCompat}from"@js-toolkit/utils/es5ErrorCompat";import{promisify}from"@js-toolkit/utils/promisify";export class FullscreenUnavailableError extends Error{constructor(){super("Fullscreen is not available"),es5ErrorCompat(this,FullscreenUnavailableError)}}export var fullscreen;!function(e){e.names=[{requestFullscreenName:"requestFullscreen",exitFullscreenName:"exitFullscreen",fullscreenElementName:"fullscreenElement",fullscreenEnabledName:"fullscreenEnabled",changeEventName:"fullscreenchange",errorEventName:"fullscreenerror"},{requestFullscreenName:"webkitRequestFullscreen",exitFullscreenName:"webkitExitFullscreen",fullscreenElementName:"webkitFullscreenElement",fullscreenEnabledName:"webkitFullscreenEnabled",changeEventName:"webkitfullscreenchange",errorEventName:"webkitfullscreenerror"},{requestFullscreenName:"webkitRequestFullScreen",exitFullscreenName:"webkitCancelFullScreen",fullscreenElementName:"webkitCurrentFullScreenElement",fullscreenEnabledName:"webkitCancelFullScreen",changeEventName:"webkitfullscreenchange",errorEventName:"webkitfullscreenerror"},{requestFullscreenName:"mozRequestFullScreen",exitFullscreenName:"mozCancelFullScreen",fullscreenElementName:"mozFullScreenElement",fullscreenEnabledName:"mozFullScreenEnabled",changeEventName:"mozfullscreenchange",errorEventName:"mozfullscreenerror"},{requestFullscreenName:"msRequestFullscreen",exitFullscreenName:"msExitFullscreen",fullscreenElementName:"msFullscreenElement",fullscreenEnabledName:"msFullscreenEnabled",changeEventName:"MSFullscreenChange",errorEventName:"MSFullscreenError"}].find((({exitFullscreenName:e})=>e in document));const n={change:e.names?.changeEventName,error:e.names?.errorEventName};function r(){if(!e.names)throw new e.UnavailableError;return Boolean(document[e.names.fullscreenElementName])}function l(e,r,l){const a=n[e];a&&document.addEventListener(a,r,l)}function a(e,r,l){const a=n[e];a&&document.removeEventListener(a,r,l)}function t(n,r){return new Promise(((t,s)=>{if(!e.names)throw new e.UnavailableError;const c=()=>{a("change",c),a("error",u),t()},u=e=>{a("change",c),a("error",u),s(e)};l("change",c),l("error",u),n[e.names.requestFullscreenName](r)}))}function s(){return new Promise(((n,t)=>{if(!e.names)throw new e.UnavailableError;if(!r())return void n();const s=()=>{a("change",s),a("error",c),n()},c=e=>{a("change",s),a("error",c),t(e)};l("change",s),l("error",c),document[e.names.exitFullscreenName]()}))}e.UnavailableError=FullscreenUnavailableError,e.isApiAvailable=function(){return!!e.names},e.isApiEnabled=function(){return!!e.names&&Boolean(document[e.names.fullscreenEnabledName])},e.isFullscreen=r,e.getElement=function(){if(!e.names)throw new e.UnavailableError;return document[e.names.fullscreenElementName]},e.on=l,e.off=a,e.request=t,e.exit=s,e.toggle=function(e){return promisify((()=>r()?s():t(e)))},e.onChange=function(e){l("change",e)},e.onError=function(e){l("error",e)}}(fullscreen||(fullscreen={}));
@@ -0,0 +1 @@
1
+ export declare function enterPseudoFullscreen(element: Element & ElementCSSInlineStyle): VoidFunction;
@@ -0,0 +1 @@
1
+ export function enterPseudoFullscreen(t){let e,i;return e={position:t.style.position,left:t.style.left,top:t.style.top,width:t.style.width,height:t.style.height,maxWidth:t.style.maxWidth,maxHeight:t.style.maxHeight,zIndex:t.style.zIndex},i=t,i.style.position="fixed",i.style.left="0px",i.style.top="0px",i.style.width="100%",i.style.height="100%",i.style.maxWidth="100%",i.style.maxHeight="100%",i.style.zIndex="99999",()=>{e&&i&&(i.style.position=e.position,i.style.left=e.left,i.style.top=e.top,i.style.width=e.width,i.style.height=e.height,i.style.maxWidth=e.maxWidth,i.style.maxHeight=e.maxHeight,i.style.zIndex=e.zIndex),e=void 0,i=void 0}}
@@ -1,11 +1,11 @@
1
- import { type Awaiter } from '@js-toolkit/utils/getAwaiter';
1
+ import { type Awaiter, type AwaiterOptions } from '@js-toolkit/utils/getAwaiter';
2
2
  import { type EmitterTarget, type EventTargetLike, type GetEventType, type GetEventTypeFromFn } from './EventEmitterListener.utils';
3
- export type EventAwaiter = Awaiter<void>;
4
- interface Options {
3
+ export type EventAwaiter = Awaiter<any>;
4
+ interface Options extends AwaiterOptions {
5
5
  /** If it returns true then resolve is ignored. */
6
6
  readonly ignoreResolve?: (event: any) => boolean;
7
7
  /** If it returns null or undefined then reject is ignored. */
8
8
  readonly eventToError?: (event: any) => unknown;
9
9
  }
10
- export declare function getEventAwaiter<T extends EmitterTarget, E extends T extends EventTargetLike ? GetEventTypeFromFn<OverloadToUnion<T['addEventListener']>> : GetEventType<T>>(target: T, resolveEvent: E | E[], rejectEvent?: E | E[], { ignoreResolve, eventToError }?: Options): EventAwaiter;
10
+ export declare function getEventAwaiter<T extends EmitterTarget, E extends T extends EventTargetLike ? GetEventTypeFromFn<OverloadToUnion<T['addEventListener']>> : GetEventType<T>>(target: T, resolveEvent: E | E[], rejectEvent?: E | E[], { ignoreResolve, eventToError, lazy, ...rest }?: Options): EventAwaiter;
11
11
  export {};
@@ -1 +1 @@
1
- import{getAwaiter}from"@js-toolkit/utils/getAwaiter";import{EventEmitterListener}from"./EventEmitterListener";import{isEventEmitterLike}from"./EventEmitterListener.utils";export function getEventAwaiter(e,t,r,{ignoreResolve:i,eventToError:o}={}){const n=getAwaiter({lazy:!0}),s=Array.isArray(t)?t:[t],E=Array.isArray(r)?r:[r],a=isEventEmitterLike(e)?e:new EventEmitterListener(e),f=e=>{!(!!i&&i(e))&&n.resolve()},m=e=>{const t=o?o(e):e;null!=t&&n.reject(t)},v=()=>{s.forEach((e=>a.off(e,f))),E.forEach((e=>a.off(e,m)))},c=n.resolve;n.resolve=(...e)=>{v(),c(...e)};const l=n.reject;return n.reject=(...e)=>{l(...e),v()},s.forEach((e=>a.on(e,f))),E.forEach((e=>a.on(e,m))),n}
1
+ import{getAwaiter}from"@js-toolkit/utils/getAwaiter";import{EventEmitterListener}from"./EventEmitterListener";import{isEventEmitterLike}from"./EventEmitterListener.utils";export function getEventAwaiter(e,t,r,{ignoreResolve:i,eventToError:o,lazy:n=!0,...s}={}){const E=getAwaiter({lazy:n,...s}),a=Array.isArray(t)?t:[t],f=Array.isArray(r)?r:[r],m=isEventEmitterLike(e)?e:new EventEmitterListener(e),v=e=>{!(!!i&&i(e))&&E.resolve(e)},c=e=>{const t=o?o(e):e;null!=t&&E.reject(t)},l=()=>{a.forEach((e=>m.off(e,v))),f.forEach((e=>m.off(e,c)))},A=E.resolve;E.resolve=(...e)=>(l(),A(...e));const y=E.reject;return E.reject=(...e)=>{y(...e),l()},a.forEach((e=>m.on(e,v))),f.forEach((e=>m.on(e,c))),E}
@@ -1,3 +1,4 @@
1
+ import log from '@js-toolkit/utils/log';
1
2
  import { type MessagesTypes } from './messages';
2
3
  import { type Target } from './utils';
3
4
  export { getClientMessages, getHostMessages } from './messages';
@@ -27,7 +28,7 @@ export type AutoConnectorOptions<SendData = AnyObject, ReceiveData = unknown> =
27
28
  readonly messagesTypes: MessagesTypes;
28
29
  /** Process messages only from targets passed to `start` method. Default `true`. */
29
30
  readonly strictTargets?: boolean;
30
- readonly logger?: Pick<Console, 'warn' | 'debug'> | undefined;
31
+ readonly logger?: Pick<log.Logger, 'v1' | 'warn'> | undefined;
31
32
  } & ({
32
33
  readonly channel: 'open' | 'use';
33
34
  readonly onConnect: (info: ConnectTargetInfo<ReceiveData>, port: MessagePort) => void;
@@ -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())},[Symbol.dispose](){this.destroy()}}}
1
+ import{v4 as uuid}from"uuid";import log from"@js-toolkit/utils/log";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:o=!0,messagesTypes:s,channel:n,logger:i=log.getLogger("AutoConnector"),onSendData:r,onConnect:a}){const d=e||uuid(),g=t||d,c=new Map,f="open"===n?new Map:void 0;let u,l;const p=(e,t,o,s,n)=>{if(window!==t)if(isWindowProxy(t)){t.postMessage(e,o,n);const r=t===window.parent?"iframe parent":"iframe";i.v1(`${g}: Post message to ${r} (uid=${s},self.uid=${d},origin=${o}):`,e)}else t.postMessage(e,n&&{transfer:n}),i.v1(`${g}: Post message to MessageEventSource (uid=${s},self.uid=${d}):`,e)},m=(e,t,o)=>{p({uid:d,type:s.Ping},e,t,o)},h=e=>{if(!e.source||e.source===window)return;if(!isPingMessage(e.data,s)&&!isTargetReadyMessage(e.data,s))return;if(e.data.uid===d)return;const t=e.source,l=e.data.uid;if(i.v1(`${g}: Receive message from iframe (uid=${l},self.uid=${d},origin=${e.origin}):`,e.data),o&&u&&!u.has(t))return void i.v1(`${g}: Could not find target (uid=${l},self.uid=${d}) by message.source.`);const h=getOriginFromMessage(e);if(isPingMessage(e.data,s)&&!c.get(l)?.Ping)return c.set(l,{...c.get(l),Ping:!0}),void m(t,h,l);let w=!1;if(c.get(l)?.Ping&&!c.get(l)?.SelfReady){c.set(l,{...c.get(l),SelfReady:!0});const e={target:t,origin:h},o=f?(()=>{const t=f.get(l)?.[0]??new MessageChannel;return f.set(l,[t,e]),t.port2})():void 0;((e,t,o,n,i)=>{p({uid:d,type:s.SelfReady,data:e},t,o,n,i?[i]:void 0)})(r?r(e):void 0,t,h,l,o),w=!1}if(isTargetReadyMessage(e.data,s)&&c.get(l)?.SelfReady){c.delete(l),u?.delete(t);const o=(()=>{if("open"===n){const e=f?.get(l)?.[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:s}=e.data,r=()=>{i.v1(`${g}: Connection established (self.uid=${d} + uid=${l}).`),a({data:s,target:t,origin:h},o)};w?setTimeout(r,0):r()}},w=()=>{l&&(l(),l=void 0)};return{start:(e,t={})=>{if(l&&!t.append)return void i.warn(`${g}: Already started. You should first call \`stop\`.`);if(t.append){const e=u;w(),u=e}const o=()=>{const o=(()=>{const t="function"==typeof e?e():e;return t.length>0?t:void 0})(),s=o&&readTargets(o);if(!s)return;const n=new Set(s);t.append?(u||(u=new Set),n.forEach((e=>u.add(e)))):u=n,window.addEventListener("message",h);(t.append?n:u).forEach((e=>{e!==window&&m(e,"*","")}))},s="function"==typeof e?onDOMReady(o):o();l=()=>{s&&s(),window.removeEventListener("message",h),u=void 0}},stop:w,isStarted:()=>!!l,close:e=>{const t=e instanceof Set?e:new Set(readTargets(e));if(0!==t.size&&(f&&f.forEach((([e,o],s)=>{t.has(o.target)&&(e.port1.close(),e.port2.close(),f.delete(s))})),u)){const e=u;t.forEach((t=>e.delete(t)))}},destroy:()=>{w(),c.clear(),f&&(f.forEach((([e])=>{e.port1.close(),e.port2.close()})),f.clear())},[Symbol.dispose](){this.destroy()}}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@js-toolkit/web-utils",
3
- "version": "1.59.1",
3
+ "version": "1.60.0",
4
4
  "description": "Web utils",
5
5
  "author": "VZH",
6
6
  "license": "MIT",
@@ -20,30 +20,30 @@
20
20
  "@js-toolkit/node-utils": "^1.2.1"
21
21
  },
22
22
  "devDependencies": {
23
- "@eslint/compat": "^1.2.5",
23
+ "@eslint/compat": "^1.2.6",
24
24
  "@eslint/eslintrc": "^3.2.0",
25
- "@eslint/js": "^9.18.0",
25
+ "@eslint/js": "^9.20.0",
26
26
  "@js-toolkit/configs": "^3.94.0",
27
- "@js-toolkit/utils": "^1.55.2",
27
+ "@js-toolkit/utils": "^1.58.0",
28
28
  "@types/eslint": "^9.6.1",
29
29
  "@types/eslint__eslintrc": "^2.1.2",
30
30
  "@types/eslint__js": "^8.42.3",
31
31
  "@types/lodash.throttle": "^4.1.9",
32
32
  "@types/uuid": "^10.0.0",
33
33
  "copyfiles": "^2.4.1",
34
- "eslint": "^9.18.0",
34
+ "eslint": "^9.20.0",
35
35
  "eslint-config-prettier": "^10.0.1",
36
36
  "eslint-plugin-import": "^2.31.0",
37
37
  "eslint-plugin-prettier": "^5.2.3",
38
38
  "eventemitter3": "^5.0.1",
39
39
  "lodash.throttle": "^4.1.1",
40
- "prettier": "^3.4.2",
40
+ "prettier": "^3.5.0",
41
41
  "reconnecting-websocket": "^4.4.0",
42
42
  "rimraf": "^6.0.1",
43
- "terser": "^5.37.0",
43
+ "terser": "^5.38.1",
44
44
  "typescript": "^5.7.3",
45
- "typescript-eslint": "^8.21.0",
46
- "ua-parser-js": "^2.0.0",
45
+ "typescript-eslint": "^8.24.0",
46
+ "ua-parser-js": "^2.0.2",
47
47
  "uuid": "^11.0.5",
48
48
  "webpack": "^5.97.1",
49
49
  "yargs": "^17.7.2"
@@ -0,0 +1,4 @@
1
+ declare global {
2
+ var TelegramWebviewProxy: AnyObject | undefined;
3
+ }
4
+ export declare function isTelegramWebView(): boolean;
@@ -0,0 +1 @@
1
+ export function isTelegramWebView(){return!!window.TelegramWebviewProxy}
@@ -1,9 +1,10 @@
1
1
  import { DataEventEmitter, type DataEventListener, type DataEventMap } from '@js-toolkit/utils/DataEventEmitter';
2
+ import log from '@js-toolkit/utils/log';
2
3
  import * as sdpUtils from './sdputils';
3
4
  export declare class PeerConnection extends DataEventEmitter<PeerConnection.EventMap, PeerConnection> implements Disposable {
4
5
  readonly options: PeerConnection.Options;
5
6
  get Events(): typeof PeerConnection.Events;
6
- readonly logger: Pick<Console, "warn" | "debug">;
7
+ readonly logger: Pick<log.Logger, "warn" | "debug">;
7
8
  private pc;
8
9
  constructor(options?: PeerConnection.Options);
9
10
  private clear;
@@ -38,7 +39,7 @@ export declare namespace PeerConnection {
38
39
  readonly offerOptions?: RTCOfferOptions;
39
40
  readonly rtc?: RTCConfiguration;
40
41
  readonly codecs?: sdpUtils.PreferCodecs;
41
- readonly logger?: Pick<Console, 'warn' | 'debug'>;
42
+ readonly logger?: Pick<log.Logger, 'debug' | 'warn'> | undefined;
42
43
  readonly id?: string;
43
44
  }
44
45
  enum Events {
@@ -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()}[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={}));
1
+ import{DataEventEmitter}from"@js-toolkit/utils/DataEventEmitter";import{getErrorMessage}from"@js-toolkit/utils/getErrorMessage";import{hasIn}from"@js-toolkit/utils/hasIn";import log from"@js-toolkit/utils/log";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??log.getLogger("PeerConnection"),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={}));