UNPKG

@salutejs/jazz-sdk-web

Version:

Jazz SDK for web applications

1,721 lines (1,494 loc) 226 kB
import { Container, Module, ModuleDeclaration } from 'ditox'; import { Controller } from 'nrgy/mvc'; import { Observable } from 'rxjs'; import { Signal, Atom, Scope } from 'nrgy'; import { Query as Query$2 } from 'rx-effects'; type EventLike$1 = { type: string; }; type KeyValueStorageEvent = { /** * The origin context of the event can be classified as 'local' when a storage * is modified by the current window or process, and as 'other' in all other cases. */ readonly context: 'local' | 'other'; /** * Returns a string with the key for the storage item that was changed. * The key attribute is null when the change is caused by the storage clear() method. */ readonly key: string | null; /** * Returns a string with the new value of the storage item that was changed. * This value is null when the change has been invoked by storage clear() method, * or the storage item has been removed from the storage. */ readonly newValue: string | null; }; /** * This is a subset of Web Storage API */ type KeyValueStorage = Readonly<{ storageEvent: Observable<KeyValueStorageEvent>; /** * Returns the current value associated with the given key, or null if the * given key does not exist in the list associated with the object. */ getItem: (key: string) => string | undefined; /** * Sets the value of the pair identified by key to value, creating a new * key/value pair if none existed for key previously. * * Throws a "QuotaExceededError" DOMException exception if the new value * couldn't be set. (Setting could fail if, e.g., the user has disabled * storage for the site, or if the quota has been exceeded.) */ setItem: (key: string, value: string) => void; /** * Removes the key/value pair with the given key from the list associated * with the object, if a key/value pair with the given key exists. */ removeItem: (key: string) => void; /** * Empties the list associated with the object of all key/value pairs, if * there are any. */ clear: () => void; getKeys: () => ReadonlyArray<string>; }>; type AnyObject = Record<string, any>; type Timestamp = number; type UTCDate = string; /** Autocomplete for string union with ability use any string * e.g. 'apple' | 'banana' | string * * WARNING: doesn't work as object key with empty default value * following code will throw type error: * const obj1: Record<Autocomplete<'foo' | 'bar'>, any> = {} */ type StringEnum<Enum extends string> = Enum | (string & Record<never, never>); type ResultFailure<Error> = { readonly type: 'failure'; readonly error: Error; }; type ResultSuccess<Value> = { readonly type: 'success'; readonly value: Value; }; type SyncResult<Value, Error = unknown> = | ResultSuccess<Value> | ResultFailure<Error>; type LogLevel = 'debug' | 'info' | 'warn' | 'error'; type LogMetadata = Readonly<Record<string, string>>; type LogEvent = Readonly<{ timestamp: number; level: LogLevel; tag: string; messages: ReadonlyArray<unknown>; meta?: LogMetadata; }>; type BaseRequestQuery = Record< string, string | boolean | number | (string | boolean | number)[] >; declare class HttpClientResponseError< ResponseError, RequestBody, RequestQuery extends BaseRequestQuery | void, > extends Error { type: 'HttpClientResponseError'; readonly request: HttpClientRequest<RequestBody, RequestQuery>; readonly status: number; readonly headers: Headers; readonly ok: false; readonly redirected: boolean; readonly statusText: string; readonly data: ResponseError; readonly originalResponse: Response; constructor( message: string, response: HttpClientResponseFailure< ResponseError, RequestBody, RequestQuery >, replaceResponseData?: ResponseError, ); } declare class HttpClientFetchError< RequestBody = void, RequestQuery extends BaseRequestQuery | void = void, > extends Error { type: 'HttpClientFetchError'; readonly request: HttpClientRequest<RequestBody, RequestQuery>; constructor( message: string, response: HttpClientErrorResponse<RequestBody, RequestQuery>, ); } type HttpClientRequest< RequestBody, RequestQuery extends BaseRequestQuery | void, > = { body: RequestBody; url: string; method: string; credentials: string; mode: string; headers: HeadersInit; query: RequestQuery; }; type HttpClientResponseFailure< ResponseError, RequestBody, RequestQuery extends BaseRequestQuery | void, > = { originalResponse: Response; status: number; headers: Headers; redirected: boolean; statusText: string; request: HttpClientRequest<RequestBody, RequestQuery>; ok: false; data: ResponseError; }; type HttpClientErrorResponse< RequestBody, RequestQuery extends BaseRequestQuery | void, > = { request: HttpClientRequest<RequestBody, RequestQuery>; }; type ApiAuthErrorResolution = 'retry' | 'fail'; type ConfigFlags<T extends Record<string, unknown>> = Readonly<T>; type ReactionType = 'applause' | 'surprise' | 'smile' | 'like' | 'dislike'; /** * @deprecated use type Atom from nrgy * Provider of a state value. */ type Query$1<T> = Query$2<T>; /** * Function which unsubscribes from something. */ type Unsubscriber$1 = () => void; /** * @deprecated use watchAtom with option.skipFirst = false * Subscribes a listener on a value of the query and its changes. * @example * ```ts import { handleQuery, } from '@salutejs/jazz-sdk-web'; ... const unsubscribe = handleQuery(room.participants, (participants) => { console.log(participants); }); unsubscribe() ``` */ declare function handleQuery<T>( query: Query$1<T> | Atom<T>, observer: (value: T) => unknown, ): Unsubscriber$1; /** * Subscribes a listener on changes of the query only. * @deprecated use watchAtom * @example * ```ts import { handleQueryChanges, } from '@salutejs/jazz-sdk-web'; ... const unsubscribe = handleQueryChanges(room.participants, (participants) => { console.log(participants); }); unsubscribe() ``` */ declare function handleQueryChanges<T>( query: Query$1<T> | Atom<T>, listener: (value: T) => unknown, ): Unsubscriber$1; /** * Subscribes to changes of the given atom and notifies the listener on new values. * * @template T - The type of the values emitted by the atom . * @param atom - An Atom to observe. * @param listener - A callback function invoked with the current or updated value. * @param options - Optional configuration: * - sync: (not currently used) potential flag to control synchronous behavior. * - onlyChanges: (not currently used) potential flag to notify only on changed values. * - skipFirst: Whether to skip the first emitted value (default: true). * * @returns A function to unsubscribe from the observed value changes. * * This function works by subscribing to the observable stream representing the atom. * If skipFirst is true, it discards the initial value emission; otherwise, it includes it. * This allows flexible control over initial notification behavior during subscription. * * @example * ```ts import { watchAtom, } from '@salutejs/jazz-sdk-web'; ... const participants = room.participants() const unsubscribe = watchAtom(room.participants, (_participants) => { participants = _participants }); unsubscribe() ``` */ declare function watchAtom<T>( atom: Atom<T> | Query$1<T>, listener: (value: T) => unknown, options?: { sync?: boolean | undefined; }, ): Unsubscriber$1; /** * Subscribes a listener on an event bus by type. * * @example * ```ts import { handleEvent, } from '@salutejs/jazz-sdk-web'; ... const unsubscribe = handleEvent( client.event$, 'addRoom', async ({ payload }) => { console.log(payload.room); }, ); unsubscribe(); ``` */ declare function handleEvent< Event extends EventLike$1, Type extends Event['type'], TypedEvent extends Event & { type: Type; }, >( eventBus: Observable<Event> | Signal<Event>, type: Type, listener: (event: TypedEvent) => unknown, isOnce?: boolean, ): Unsubscriber$1; /** * Subscribes a listener on an event bus. * * @example * ```ts import { handleEvents, } from '@salutejs/jazz-sdk-web'; ... const unsubscribe = handleEvents(client.event$, (event) => { if (event.type === 'addRoom') { console.log(payload.room); } }); unsubscribe() ``` */ declare function handleEvents<Event extends EventLike$1>( eventBus: Observable<Event> | Signal<Event>, listener: (event: Event) => unknown, isOnce?: boolean, ): Unsubscriber$1; type PayloadError<Code, Params> = { code: Code; reason?: Code; message?: string; params?: Params; }; type RequestId = string; type EventOk<T = string, P = unknown> = { event: T; requestId: RequestId; roomId: string; groupId: string | undefined; payload: P; }; type EventError< Code = string, Params = unknown, Error extends string = 'error', > = { event: Error; requestId: RequestId; roomId: string; groupId: string | undefined; payload: PayloadError<Code, Params>; }; /** * Event name for subscribe to all events in transport */ declare type AllEventTypes = '*'; declare type AllNodeTypes = | TransportRoot<any> | BaseTransportNode | BaseTransportNodeReadonly; declare interface BaseEventBusReadonly<EVENTS extends EventLike> extends BaseEventBusSubscriber<EVENTS> { name?: string; } declare interface BaseEventBusSubscriber<EVENTS extends EventLike> { /** * Method for subscribing to bus events. * In addition to events of the type, you can also specify the * event, * which will allow you to subscribe to all bus events. * The method returns a function for unsubscribing the callback * (this can also be done via the off or removeEventListener methods). * * If the onSubscribe lifecycle method is passed, * it will be called when this event is sent. * * If the transport was destroyed, this method will do nothing. * * @example * ```ts * type Events = { event: string }; * const eventBus = createBaseEventBus<Events>(); * * const unsubscriber = eventBus.on('event', (event, payload) => console.log(payload)); * unsubscriber(); * * eventBus.send('event', 'test'); * ``` */ on<EVENT extends string & keyof EVENTS>( event: EVENT, callback: (event: EVENT, payload: EVENTS[EVENT]) => void, ): Unsubscriber; /** * unsubscribe from an event. * If there are no subscribers left for the event, we remove it from the map. * * If the onUnsubscribe lifecycle callback is passed, * it will be called each time this function is called. * * If the transport was destroyed, the method does not work. * * @example * ```ts * type Events = { event: string }; * const eventBus = createBaseEventBus<Events>(); * * function handler(type: string, payload: string): void {} * * eventBus.on('event', handler); * eventBus.off('event', handler); * ``` */ off<EVENT extends string & keyof EVENTS>( event: EVENT, callback: (event: EVENT, payload: EVENTS[EVENT]) => void, ): void; } declare interface BaseTransportNode extends DestroyedNode { name?: string; __isRoot: Readonly<false>; /** * Method to get the root node object referenced by the node. */ getTransports: () => TransportRootNodes; } declare interface BaseTransportNodeReadonly { name?: string; __isRoot: Readonly<false>; /** * A property indicating that a class has been destroyed. * Once resolved, all methods in it stop working and the data is cleared. */ isDestroyed: boolean; /** * Method to get the root node object referenced by the node. */ getTransports: () => TransportRootNodes; } declare interface BaseTransportRoot extends DestroyedNode { name?: string; __isRoot: Readonly<true>; } /** * A node that has a cleanup mechanism. After the method chchchch is executed, * the node becomes inactive because event subscriptions and message sending stop functioning. */ declare interface DestroyedNode { /** * whether the transport is destroyed. * If the transport is destroyed, * then subscriptions and event sending do not work, and the subscriber list is destroyed. * Also, all dependent nodes are automatically unsubscribed from the destroyed node. */ isDestroyed: boolean; destroy(): void; } declare type EventLike = Record<string, unknown>; declare type Namespace = string; declare interface SubscribeNode<EVENTS extends EventLike> extends TransportNodeBase<EVENTS> { add< TYPES extends string & keyof EVENTS, TYPE extends Type, ALL_NAMESPACES extends UtilsTypeFilterTypesWithNamespaces<TYPES, TYPE>, >( namespace: ALL_NAMESPACES | '', root: AllNodeTypes, ): void; remove< TYPES extends string & keyof EVENTS, TYPE extends Type, ALL_NAMESPACES extends UtilsTypeFilterTypesWithNamespaces<TYPES, TYPE>, >( namespace: ALL_NAMESPACES | '', root: AllNodeTypes, ): void; channel< EVENT_TYPES extends string & keyof EVENTS, TYPES extends string, CHANNEL extends UtilsTypeFilterTypesWithNamespaces<EVENT_TYPES, TYPES>, CHANNEL_EVENTS_TYPES extends UtilsTypeRemoveNamespaceFromType< EVENT_TYPES, CHANNEL >, CHANNEL_EVENTS extends { [TYPE in CHANNEL_EVENTS_TYPES]: EVENTS[`${CHANNEL}:${TYPE}`]; }, >( channel: CHANNEL, ): SubscribeNode<CHANNEL_EVENTS>; asReadonly(): SubscribeReadonlyNode<EVENTS>; } declare interface SubscribeNodeSubscribers<EVENTS extends EventLike> { on< EVENTS_KEYS extends keyof EVENTS, TYPE extends string, NAMESPACES extends UtilsTypeFilterTypesWithNamespaces< string & EVENTS_KEYS, TYPE >, EVENT_TYPE extends | `${NAMESPACES}:${AllEventTypes}` | AllEventTypes | (string & EVENTS_KEYS), NEW_NAMESPACE extends UtilsTypeFilterTypesWithNamespaces<EVENT_TYPE, TYPE>, CALLBACK_EVENTS extends EVENT_TYPE extends AllEventTypes ? string & EVENTS_KEYS : EVENT_TYPE extends `${NAMESPACES}:${AllEventTypes}` ? UtilsTypeRemoveNamespaceFromType<string & EVENTS_KEYS, NEW_NAMESPACE> : EVENT_TYPE, CALLBACK_PARAMS extends { [TYPE in CALLBACK_EVENTS]: [event: TYPE, payload: EVENTS[TYPE]]; }, >( event: EVENT_TYPE, callback: (...args: CALLBACK_PARAMS[CALLBACK_EVENTS]) => void, ): Unsubscriber; once< EVENTS_KEYS extends keyof EVENTS, TYPE extends string, NAMESPACES extends UtilsTypeFilterTypesWithNamespaces< string & EVENTS_KEYS, TYPE >, EVENT_TYPE extends | `${NAMESPACES}:${AllEventTypes}` | AllEventTypes | (string & EVENTS_KEYS), NEW_NAMESPACE extends UtilsTypeFilterTypesWithNamespaces<EVENT_TYPE, TYPE>, CALLBACK_EVENTS extends EVENT_TYPE extends AllEventTypes ? string & EVENTS_KEYS : EVENT_TYPE extends `${NAMESPACES}:${AllEventTypes}` ? UtilsTypeRemoveNamespaceFromType<string & EVENTS_KEYS, NEW_NAMESPACE> : EVENT_TYPE, CALLBACK_PARAMS extends { [TYPE in CALLBACK_EVENTS]: [event: TYPE, payload: EVENTS[TYPE]]; }, >( event: EVENT_TYPE, callback: (...args: CALLBACK_PARAMS[CALLBACK_EVENTS]) => void, ): Unsubscriber; off< EVENTS_KEYS extends keyof EVENTS, TYPE extends string, NAMESPACES extends UtilsTypeFilterTypesWithNamespaces< string & EVENTS_KEYS, TYPE >, EVENT_TYPE extends | `${NAMESPACES}:${AllEventTypes}` | AllEventTypes | (string & EVENTS_KEYS), >( type: EVENT_TYPE, callback: (...args: any[]) => void, ): void; } declare interface SubscribeReadonlyNode<EVENTS extends EventLike> extends SubscribeReadonlyNodeExtends<EVENTS> {} declare type SubscribeReadonlyNodeExtends<EVENTS extends EventLike> = BaseTransportNodeReadonly & SubscribeNodeSubscribers<EVENTS>; declare type TransportLifecycleEvents<EVENTS extends EventLike> = { /** * The transport was cleared. After that, * it stops functioning and all data in it is cleared. */ destroy: undefined; /** * Subscribed to some event. * The object indicates what event was subscribed to and whether it is the first. */ subscribe: { event: string & keyof EVENTS; mode: 'on' | 'once'; subscriber: Parameters<TransportRootSubscribers<EVENTS>['on']>[1]; subscribersCount: number; }; /** * Unsubscribed from some event. * The object indicates what event was unsubscribed from and whether there are more subscribers. */ unsubscribe: { event: string & keyof EVENTS; mode: 'on' | 'once'; subscriber: Parameters<TransportRootSubscribers<EVENTS>['off']>[1]; subscribersCount: number; }; }; declare type TransportNodeBase<EVENTS extends EventLike> = SubscribeNodeSubscribers<EVENTS> & BaseTransportNode; declare interface TransportReadonlyNode<EVENTS extends EventLike> extends TransportReadonlyNodeBase<EVENTS> { lifecycle: TransportRoot<EVENTS>['lifecycle']; } declare type TransportReadonlyNodeBase<EVENTS extends EventLike> = TransportRootSubscribers<EVENTS> & BaseTransportNodeReadonly; declare interface TransportRoot<EVENTS extends EventLike> extends TransportRootBase<EVENTS> { /** * Sync mode sending events * * @default false */ sync?: Readonly<boolean>; /** * Method for sending an event to listeners. * If the transport was destroyed, * or no one is subscribed to this event, the method will do nothing. * * If there are subscribers to *, * they will listen to all events that were forwarded. * * The method works in 2 modes: synchronous and asynchronous (asynchronous mode is enabled by default). * To change this, you need to pass the 3rd argument. * * @example * ```ts * type Events = { event: string, event_empty: undefined }; * const transport = createTransport<Events>(); * * transport.on('event', (event, payload) => console.log(payload)); * transport.on('event_empty', (event, payload) => console.log(payload)); * transport.on('*', (event, payload) => console.log(payload)); * * transport.send('event', 'test'); * transport.send('event_empty'); * transport.send('event_empty', undefined); * ``` */ send< TYPE extends string & keyof EVENTS, PARAMETERS extends EVENTS[TYPE] extends undefined ? (payload?: EVENTS[TYPE]) => void : (payload: EVENTS[TYPE]) => void, >( type: TYPE, ...other: Parameters<PARAMETERS> ): void; /** * Method for getting a node that has only subscription interfaces (on/once/off). * Recommended for use in public API services to hide methods * for direct control of transport state from the outside. */ asReadonly(): TransportReadonlyNode<EVENTS>; } declare type TransportRootBase<EVENTS extends EventLike> = TransportRootSubscribers<EVENTS> & BaseTransportRoot & { /** * Transport lifecycle event bus. You can subscribe to 3 events: * 1) destroy - the transport was cleared. After that, it stops functioning and all data in it is cleared. * 2) subscribe - subscribed to some event. The object indicates what event was subscribed to and whether it is the first. * 3) unsubscribe - unsubscribed from some event. The object indicates what event was unsubscribed from and whether there are more subscribers. * * When the main transport is destroyed, the lifecycle event bus also dies. * * @example * ```ts * const transport = createTransport<Events>(); * * transport.lifecycle.on('destroy', () => console.log('transport is destroy')); * transport.lifecycle.on('subscribe', ({ event, isFirstSubscribe }) => console.log(`subscribe to event ${event} isFirst=${isFirstSubscribe}`)); * transport.lifecycle.on('unubscribe', ({ event, isHasSubscribers }) => console.log(`unsubscribe from event ${event} isHasSubscribers=${isHasSubscribers}`)); * * const unsubscriber1 = transport.on('event1', () => {}) // subscribe to event event1 isFirst=true * const unsubscriber2 = transport.on('event1', () => {}) // subscribe to event event1 isFirst=false * const unsubscriber3 = transport.on('event2', () => {}) // subscribe to event event2 isFirst=true * * unsubscriber3() // unsubscribe from event event2 isHasSubscribers=false * unsubscriber2() // unsubscribe from event event1 isHasSubscribers=true * unsubscriber1() // unsubscribe from event event1 isHasSubscribers=false * * transport.destroy(); // transport is destroy * ``` */ lifecycle: Readonly< BaseEventBusReadonly<TransportLifecycleEvents<EVENTS>> >; }; /** * List of nodes the node is subscribed to. */ declare type TransportRootNodes = Record<Namespace, Array<TransportRoot<any>>>; declare interface TransportRootSubscribers<EVENTS extends EventLike> { /** * Method for subscribing to bus events. * In addition to events of the type, you can also specify the * event, * which will allow you to subscribe to all bus events. * The method returns a function for unsubscribing the callback * (this can also be done via the off or removeEventListener methods). * * If the onSubscribe lifecycle method is passed, * it will be called when this event is sent. * * If the transport was destroyed, this method will do nothing. * * @example * ```ts * type Events = { event: string }; * const transport = createTransport<Events>(); * * transport.on('event', (event, payload) => console.log(payload)); * const unsubscriber = transport.on('*', (event, payload) => console.log(payload)); * unsubscriber(); * * transport.send('event', 'test'); * ``` */ on< EVENT_TYPE extends string & (keyof EVENTS | AllEventTypes), EVENT extends EVENT_TYPE extends AllEventTypes ? string & keyof EVENTS : EVENT_TYPE, CB extends { [TYPE in EVENT]: [TYPE, EVENTS[TYPE]]; }, >( event: EVENT_TYPE, callback: (...args: CB[EVENT]) => void, ): Unsubscriber; /** * A method for one-time subscription to bus events. * In addition to events of the type, you can also specify an event *, * which will allow you to subscribe to all bus events. * The method returns a function for unsubscribing the callback * (this can also be done via the off or removeEventListener methods). * * If the onSubscribe lifecycle method is passed, * it will be called when this event is sent. * * If the transport was destroyed, this method will do nothing. * * @example * ```ts * type Events = { event: string }; * const transport = createTransport<Events>(); * * transport.once('event', (event, payload) => console.log(payload)); * const unsubscriber = transport.once('*', (event, payload) => console.log(payload)); * unsubscriber(); * * transport.send('event', 'test'); * transport.send('event', 'test'); // not call subscribers * ``` */ once< EVENT_TYPE extends string & (keyof EVENTS | AllEventTypes), EVENT extends EVENT_TYPE extends AllEventTypes ? string & keyof EVENTS : EVENT_TYPE, CB extends { [TYPE in EVENT]: [TYPE, EVENTS[TYPE]]; }, >( event: EVENT_TYPE, callback: (...args: CB[EVENT]) => void, ): Unsubscriber; /** * unsubscribe from an event. * If there are no subscribers left for the event, we remove it from the map. * * If the onUnsubscribe lifecycle callback is passed, * it will be called each time this function is called. * * If the transport was destroyed, the method does not work. * * @example * ```ts * type Events = { event: string }; * const transport = createTransport<Events>(); * * function handler(type: string, payload: string): void {} * * transport.on('event', handler); * transport.off('event', handler); * ``` */ off<EVENT_TYPE extends string & (keyof EVENTS | AllEventTypes)>( event: EVENT_TYPE, callback: (...args: any[]) => void, ): void; } declare type Type = string; /** * unsubscribe function to unsubscribe from an event. */ declare type Unsubscriber = () => void; /** * Utility type for adding to namespace event names * * @example * * type Event = { event1: boolean; event2: number; } * UtilsTypeAddNamespaceToEvents<'namespace', Event> // { 'namespace:event1': boolean; 'namespace:event2': number; } */ declare type UtilsTypeAddNamespaceToEvents< NAMESPACE extends string, EVENT extends EventLike, > = NAMESPACE extends '' ? EVENT : { [TYPE in UtilsTypeAddNamespaceToType< NAMESPACE, string & keyof EVENT >]: EVENT[UtilsTypeRemoveNamespaceFromType<TYPE, NAMESPACE>]; }; /** * Utility type for gluing namespace and type name * * @example * UtilsTypeAddNamespaceToType<'namespace', 'type'> // 'namespace:type' */ declare type UtilsTypeAddNamespaceToType< NAMESPACE extends string, TYPE extends string, > = `${NAMESPACE}:${TYPE}`; /** * Utility type for getting namespace from event name (max size 5 namespaces) * * @example * * UtilsTypeFilterTypesWithNamespaces<'namespace1:event', 'event'> // 'namespace1' * UtilsTypeFilterTypesWithNamespaces<'namespace1:namespace2:event', 'event'> // 'namespace1:namespace2' * UtilsTypeFilterTypesWithNamespaces<'namespace1:namespace2:namespace3:event', 'event'> // 'namespace1:namespace2:namespace3' */ declare type UtilsTypeFilterTypesWithNamespaces< STR extends string, TYPE extends string, > = STR extends `${infer NAMESPACE_1}:${infer NAMESPACE_2}:${infer NAMESPACE_3}:${infer NAMESPACE_4}:${infer NAMESPACE_5}:${TYPE}` ? `${NAMESPACE_1}:${NAMESPACE_2}:${NAMESPACE_3}:${NAMESPACE_4}:${NAMESPACE_5}` : STR extends `${infer NAMESPACE_1}:${infer NAMESPACE_2}:${infer NAMESPACE_3}:${infer NAMESPACE_4}:${TYPE}` ? `${NAMESPACE_1}:${NAMESPACE_2}:${NAMESPACE_3}:${NAMESPACE_4}` : STR extends `${infer NAMESPACE_1}:${infer NAMESPACE_2}:${infer NAMESPACE_3}:${TYPE}` ? `${NAMESPACE_1}:${NAMESPACE_2}:${NAMESPACE_3}` : STR extends `${infer NAMESPACE_1}:${infer NAMESPACE_2}:${TYPE}` ? `${NAMESPACE_1}:${NAMESPACE_2}` : STR extends `${infer NAMESPACE}:${TYPE}` ? `${NAMESPACE}` : never; /** * Utility type of extraction from event name type without namespace * * @example * UtilsTypeRemoveNamespaceFromType<'namespace:event', 'namespace'> // 'event' */ declare type UtilsTypeRemoveNamespaceFromType< NAMESPACED_TYPE extends string, NAMESPACE extends string, > = NAMESPACED_TYPE extends `${NAMESPACE}:${infer TYPE}` ? TYPE : never; type JitsiXmppEvents = { /** * Indicates error while adding ice candidate. */ 'xmpp.add_ice_candidate_failed': []; // Designates an event indicating that the focus has asked us to mute our // audio. 'xmpp.audio_muted_by_focus': []; // Designates an event indicating that the focus has asked us to disable our // camera. 'xmpp.video_muted_by_focus': []; 'xmpp.authentication_required': []; 'xmpp.bridge_down': []; /** * Triggered when 'session-accept' is received from the responder. */ 'xmpp.callaccepted.jingle': []; // Designates an event indicating that an offer (e.g. Jingle // session-initiate) was received. 'xmpp.callincoming.jingle': []; // Triggered when Jicofo kills our media session, this can happen while // we're still in the MUC, when it decides to terminate the media session. // For example when the session is idle for too long, because we're the only // person in the conference room. 'xmpp.callended.jingle': []; 'xmpp.chat_error_received': []; // The conference properties (as advertised by jicofo) have changed 'xmpp.conference_properties_changed': []; /** * This event is triggered when the ICE connects for the first time. */ 'xmpp.connection.connected': []; // Designates an event indicating that the connection to the XMPP server // failed. 'xmpp.connection.failed': []; // Designates an event indicating that the media (ICE) connection was // interrupted. This should go to the RTC module. 'xmpp.connection.interrupted': []; // Designates an event indicating that the media (ICE) connection was // restored. This should go to the RTC module. 'xmpp.connection.restored': []; // Designates an event indicating that the media (ICE) connection failed. // This should go to the RTC module. 'xmpp.connection.ice.failed': []; // Designates an event indicating that the call has been migrated to a different // bridge and that the client needs to be restarted for a successful transition. 'xmpp.connection.restart': []; /** * Designates an event indicating connection status changes. */ 'xmpp.connection.status.changed': []; // Designates an event indicating that the display name of a participant // has changed. 'xmpp.display_name_changed': []; /** * Chat room instance have been added to Strophe.emuc plugin. */ 'xmpp.emuc_room_added': []; /** * Chat room instance have been removed from Strophe.emuc plugin. */ 'xmpp.emuc_room_removed': []; 'xmpp.etherpad': []; 'xmpp.focus_disconnected': []; 'xmpp.focus_left': []; 'xmpp.graceful_shutdown': []; /** * Event fired when 'transport-replace' Jingle message has been received, * before the new offer is set on the PeerConnection. */ 'rtc.ice_restarting': []; /** * Event fired after the 'transport-replace' message has been processed * and the new offer has been set successfully. */ 'rtc.ice_restart_success': []; /** * Designates an event indicating that we were kicked from the XMPP MUC. * @param {boolean} isSelfPresence - whether it is for local participant * or another participant. * @param {string} actorJid - the jid of the participant who was initator * of the kick. * @param {?string} participantJid - when it is not a kick for local participant, * this is the jid of the participant which was kicked. */ 'xmpp.kicked': []; // Designates an event indicating that our role in the XMPP MUC has changed. 'xmpp.localrole_changed': []; /** * Event fired when the unique meeting id is set. */ 'xmpp.meeting_id_set': []; // Designates an event indicating that an XMPP message in the MUC was // received. 'xmpp.message_received': []; // Designates an event indicating that an invite XMPP message in the MUC was // received. 'xmpp.invite_message_received': [ roomJid: string, from: string, txt: string, invitePassword: string, ]; // Designates an event indicating that a private XMPP message in the MUC was // received. 'xmpp.private_message_received': []; // Designates an event indicating that a bot participant type had changed 'xmpp.muc_member_bot_type_changed': []; // Designates an event indicating that the XMPP MUC was destroyed. 'xmpp.muc_destroyed': []; // Designates an event indicating that we have joined the XMPP MUC. 'xmpp.muc_joined': []; // Designates an event indicating that a participant joined the XMPP MUC. 'xmpp.muc_member_joined': []; // Designates an event indicating that a participant left the XMPP MUC. 'xmpp.muc_member_left': []; // Designates an event indicating that a participant joined the lobby XMPP MUC. 'xmpp.muc_lobby_member_joined': []; // Designates an event indicating that a participant in the lobby XMPP MUC has been updated 'xmpp.muc_lobby_member_updated': []; // Designates an event indicating that a participant left the XMPP MUC. 'xmpp.muc_lobby_member_left': []; // Designates an event indicating that a participant was denied access to a conference from the lobby XMPP MUC. 'xmpp.muc_denied access': []; // Designates an event indicating that local participant left the muc 'xmpp.muc_left': []; // Designates an event indicating that the MUC role of a participant has // changed. 'xmpp.muc_role_changed': []; // Designates an event indicating that the MUC has been locked or unlocked. 'xmpp.muc_lock_changed': []; // Designates an event indicating that the MUC members only config has changed. 'xmpp.muc_members_only_changed': []; // Designates an event indicating that a participant in the XMPP MUC has // advertised that they have audio muted (or unmuted). 'xmpp.audio_muted': []; // Designates an event indicating that a participant in the XMPP MUC has // advertised that they have video muted (or unmuted). 'xmpp.video_muted': []; // Designates an event indicating that the video type (e.g. 'camera' or // 'screen') for a participant has changed. // Note: currently this event fires every time we receive presence from // someone (regardless of whether or not the "video type" changed). 'xmpp.video_type': []; /** * Indicates that the features of the participant has been changed. */ 'xmpp.participant_features_changed': []; 'xmpp.password_required': []; /** * Indicates that phone number changed. */ 'conference.phoneNumberChanged': []; 'xmpp.presence_received': []; 'xmpp.presence_status': []; 'xmpp.prompt_for_login': []; // xmpp is connected and obtained user media 'xmpp.ready_to_join': []; /** * Indicates that recording state changed. */ 'xmpp.recorderStateChanged': []; // Designates an event indicating that we received statistics from a // participant in the MUC. 'xmpp.remote_stats': []; /** * Indicates that the offer / answer renegotiation has failed. */ 'xmpp.renegotiation_failed': []; 'xmpp.room_reservation_error': []; 'xmpp.room_connect_error': []; 'xmpp.room_connect_error.not_allowed': []; 'xmpp.room_join_error': []; 'xmpp.room_connect_error.members_only': []; /** * Indicates that max users limit has been reached. */ 'xmpp.room_max_users_error': []; // Designates an event indicating that we sent an XMPP message to the MUC. 'xmpp.sending_chat_message': []; // Designates an event indicating that we sent a private XMPP message to // a specific user of the muc. 'xmpp.sending_private_chat_message': []; // Event fired after receiving the confirmation about session accept. 'xmpp.session_accept': []; // Event fired if we receive an error after sending the session accept. 'xmpp.session_accept_error': []; /** * Event fired when we do not get our 'session-accept' acknowledged by * Jicofo. It most likely means that there is serious problem with our * connection or XMPP server and we should reload the conference. * * We have seen that to happen in BOSH requests race condition when the BOSH * request table containing the 'session-accept' was discarded by Prosody. * Jicofo does send the RESULT immediately without any condition, so missing * packets means that most likely it has never seen our IQ. */ 'xmpp.session_accept_timeout': []; /** * Event fired when speaker stats update message is received. */ 'xmpp.speaker_stats_received': []; /** * Event fired when conference creation timestamp is received. */ 'xmpp.conference_timestamp_received': []; /** * Event fired when we receive a message for AV moderation approved for the local participant. */ 'xmpp.av_moderation.approved': []; /** * Event fired when we receive a message for AV moderation. */ 'xmpp.av_moderation.received': []; /** * Event fired when the moderation enable/disable changes. */ 'xmpp.av_moderation.changed': []; /** * Event fired when we receive message that a new jid was approved. */ 'xmpp.av_moderation.participant.approved': []; // Designates an event indicating that we should join the conference with // audio and/or video muted. 'xmpp.start_muted_from_focus': []; // Designates an event indicating that the subject of the XMPP MUC has // changed. 'xmpp.subject_changed': []; // FIXME: how does it belong to XMPP ? - it's detected by the PeerConnection // suspending detected 'xmpp.suspend_detected': []; /** * Notifies for transcription status changes. The event provides the * following parameters to its listeners: * * @param {String} status - The new status. */ 'xmpp.transcription_status_changed': []; /** * Event fired when 'transport-info' with new ICE candidates is received. */ 'xmpp.transportinfo.jingle': []; /** * Indicates that video SIP GW state changed. * * @param {VideoSIPGWConstants} status - Any of the following statuses: * STATUS_BUSY, STATUS_AVAILABLE or STATUS_UNDEFINED. */ 'xmpp.videoSIPGWAvailabilityChanged': []; /** * Indicates that video SIP GW Session state changed. * The statuses are any of the following statuses: * STATE_ON, STATE_OFF, STATE_PENDING, STATE_RETRYING, STATE_FAILED. * {@see VideoSIPGWConstants} * * @param {options} event - {address, oldState, newState, displayName}. */ 'xmpp.videoSIPGWSessionStateChanged': []; // Designates an event indicating that the local ICE connection state has // changed. 'xmpp.ice_connection_state_changed': []; /** * Event which is emitted when the body in an XMPP message in the MUC * contains JSON */ 'xmmp.json_message_received': [from: string, data: unknown]; }; type JitsiXmppEventType$1 = keyof JitsiXmppEvents; type JitsiRTCEventType$1 = /** * Indicates error while create answer call. */ | 'rtc.create_answer_failed' /** * Indicates error while create offer call. */ | 'rtc.create_offer_failed' | 'rtc.data_channel_open' | 'rtc.endpoint_conn_status_changed' | 'rtc.dominant_speaker_changed' | 'rtc.lastn_endpoint_changed' /** * Event emitted when the user granted/blocked a permission for the camera / mic. * Used to keep track of the granted permissions on browsers which don't * support the Permissions API. */ | 'rtc.permissions_changed' | 'rtc.sender_video_constraints_changed' /** * Event emitted when {@link RTC.setLastN} method is called to update with * the new value set. * The first argument is the value passed to {@link RTC.setLastN}. */ | 'rtc.lastn_value_changed' /** * Event emitted when ssrc for a local track is extracted and stored * in {@link TraceablePeerConnection}. * @param {JitsiLocalTrack} track which ssrc was updated * @param {string} ssrc that was stored */ | 'rtc.local_track_ssrc_updated' /** * The max enabled resolution of a local video track was changed. */ | 'rtc.local_track_max_enabled_resolution_changed' | 'rtc.track_attached' /** * Event fired when we remote track is added to the conference. * 1st event argument is the added <tt>JitsiRemoteTrack</tt> instance. **/ | 'rtc.remote_track_added' // FIXME get rid of this event in favour of NO_DATA_FROM_SOURCE event // (currently implemented for local tracks only) | 'rtc.remote_track_mute' /** * Indicates that the remote track has been removed from the conference. * 1st event argument is the removed {@link JitsiRemoteTrack} instance. */ | 'rtc.remote_track_removed' // FIXME get rid of this event in favour of NO_DATA_FROM_SOURCE event // (currently implemented for local tracks only) | 'rtc.remote_track_unmute' /** * Indicates error while set local description. */ | 'rtc.set_local_description_failed' /** * Indicates error while set remote description. */ | 'rtc.set_remote_description_failed' | 'rtc.audio_output_device_changed' | 'rtc.device_list_changed' /** * Indicates that the list with available devices will change. */ | 'rtc.device_list_will_change' | 'rtc.device_list_available' /** * Indicates that a message from another participant is received on * data channel. */ | 'rtc.endpoint_message_received' /** * Indicates that the remote endpoint stats have been received on data channnel. */ | 'rtc.endpoint_stats_received' /** * Designates an event indicating that the local ICE username fragment of * the jingle session has changed. * The first argument of the vent is <tt>TraceablePeerConnection</tt> which * is the source of the event. * The second argument is the actual "ufrag" string. */ | 'rtc.local_ufrag_changed' /** * Designates an event indicating that the local ICE username fragment of * the jingle session has changed. * The first argument of the vent is <tt>TraceablePeerConnection</tt> which * is the source of the event. * The second argument is the actual "ufrag" string. */ | 'rtc.remote_ufrag_changed' /** * Custom server messages */ | `rtc.datachannel.${string}`; type JitsiRTCEventType = JitsiRTCEventType$1; type JitsiXmppEventType = JitsiXmppEventType$1; type JitsiOutputType = 'video' | 'audio'; type JitsiVideoType = 'camera' | 'desktop'; // Not typed yet // eslint-disable-next-line @typescript-eslint/no-explicit-any type UntypedCallback = (...data: any[]) => void; type PayloadObject = object; interface JitsiTrack { containers: HTMLMediaElement[]; disposed: boolean; track: MediaStreamTrack; stream: MediaStream; videoType?: JitsiVideoType; ssrc?: number; // For local tracks maxEnabledResolution?: number; isAudioTrack(): boolean; isWebRTCTrackMuted(): boolean; isVideoTrack(): boolean; isLocal(): boolean; isLocalAudioTrack(): boolean; isActive(): boolean; isMuted(): boolean; getType(): JitsiOutputType; getOriginalStream(): MediaStream | null; getStreamId(): string | null; getTrack(): MediaStreamTrack; getTrackLabel(): string; getTrackId(): string | null; getUsageLabel(): JitsiVideoType | 'mic' | 'default'; getId(): string | null; getParticipantId(): string | null; getSourceName(): string | null; attach(element: HTMLVideoElement | HTMLAudioElement): void; detach(element: HTMLVideoElement | HTMLAudioElement): void; dispose(): Promise<void>; // audioLevel: value between 0 and 1 setAudioLevel(audioLevel: number, tpc: TraceablePeerConnection): void; getMSID(): string | null; setAudioOutput(audioOutputDeviceId: string): Promise<void>; addEventListener(event: string, callback: UntypedCallback): void; removeEventListener(event: string, callback: UntypedCallback): void; } interface JitsiRemoteTrack extends JitsiTrack { isP2P: boolean; setMute(value: boolean): void; getSSRC(): number; // synchronization source identifier _getStatus(): `readyState: ${MediaStreamTrackState}, muted: ${boolean}, enabled: ${boolean}`; toString(): `RemoteTrack[userID: ${string}, type: ${JitsiOutputType}, ssrc: ${number}, p2p: ${boolean}, status: ${ReturnType< JitsiRemoteTrack['_getStatus'] >}]`; } type JitsiLocalTrackEffect = Readonly<{ isEnabled: (track: JitsiLocalTrack) => boolean; isMuted?: () => boolean; setMuted?: (muted: boolean) => void; startEffect: (stream: MediaStream) => MediaStream | null; stopEffect: () => void; // Jazz custom prop key?: string; // Jazz custom prop order?: 'start' | 'end'; }>; interface JitsiLocalTrack extends JitsiTrack { _realDeviceId: string; deviceId: string; isEnded(): boolean; getCameraFacingMode(): 'environment' | 'user' | undefined; getDeviceId(): string; setEffect(effect: JitsiLocalTrackEffect | undefined): Promise<void>; setConference(conference: JitsiConference | null): void; mute(): Promise<void>; unmute(): Promise<void>; stopStream(): void; toString(): string; _originalStream: MediaStream | null; rtcId: number; conference: JitsiConference | null; // Jazz custom addEffect(effect: JitsiLocalTrackEffect): Promise<void>; // Jazz custom removeEffect(key?: string): Promose<void>; // Jazz custom removeEffects(): Promose<void>; } type TPCGroupInfo = { /** the SSRC groups semantics */ semantics: string; /** group's SSRCs in order where the first one is group's primary SSRC, * the second one is secondary (RTX) and so on... */ ssrcs: Array<number>; }; type TPCSSRCInfo = { /** an array which holds all track's SSRCs */ ssrcs: Array<number>; /** an array stores all track's SSRC groups */ groups: Array<TPCGroupInfo>; }; type TraceablePeerConnection = { peerconnection?: RTCPeerConnection; localSSRCs: Map<string, TPCSSRCInfo>; getLocalSSRC(localTrack: JitsiTrack): number | undefined; isSimulcastOn(): boolean; getActiveSimulcastStreams(): number; getTargetVideoBitrates(): Record<string, number>; getConfiguredVideoCodec(): string; configureSenderVideoEncodings(): void; }; interface JitsiConnectionOptions { billingId?: string; hosts: { domain: string; muc?: string; bridge?: string; focus?: string; }; bosh?: string; websocket?: string; clientNode?: string; serviceUrl?: string; confID?: string; siteID?: string; startSilent?: boolean; applicationName?: string; resolution?: number; constraints?: { video: { aspectRatio: number; height: { ideal: number; max: number; min: number; }; width: { ideal: number; max: number; min: number; }; }; }; enableWebsocketResume?: boolean; enableNoAudioDetection?: boolean; enableNoisyMicDetection?: boolean; enableTalkWhileMuted?: boolean; enableUnifiedOnChrome?: boolean; enableLayerSuspension?: boolean; channelLastN?: number; disableSimulcast?: boolean; audioQuality?: { stereo?: boolean; opusMaxAverageBitrate?: number; // 6000 - 510000 }; videoQuality?: { preferredCodec?: string; enforcePreferredCodec?: boolean; disabledCodec?: string; maxBitratesVideo?: { low: number; standard: number; high: number; }; desktopBitrate?: number; configureVP9?: boolean; // custom flag for jazz. see patch 28_vp9-encodings. multiplierVP9?: number; // custom flag for jazz. see patch 28_vp9-encodings. }; p2p?: { enabled?: boolean; disabledCodec?: string; preferredCodec?: string; }; enableForcedReload?: boolean; enableIceRestart?: boolean; desktopSharingFrameRate?: { min: number; max: number; }; /** Use TURN/UDP servers for the jitsi-videobridge connection */ useTurnUdp?: boolean; useNewBandwidthAllocationStrategy?: boolean; websocketKeepAlive?: number; } interface JitsiConferenceOptions extends Omit<JitsiConnectionOptions, 'p2p'> { openBridgeChannel?: string; startSilent?: boolean; p2p?: { enabled?: boolean; }; } interface JitsiUser { getId(): string; getJid(): string; getDisplayName(): string | undefined; getRole(): string; isAudioMuted(): boolean; isVideoMuted(): boolean; getStatus(): string; getConnectionStatus(): string; hasAnyVideoTrackWebRTCMuted(): boolean; isHidden(): boolean; isReplacing(): boolean; isReplaced(): boolean; getBotType(): string | undefined; getTracks(): Array<JitsiTrack>; } interface JitsiCommand { value?: string; attributes?: Record<string, string | undefined>; children?: JitsiCommand[]; tagName?: string; } interface DownloadUploadStats { download: number; upload: number; } interface JitsiBridgeStats { bitrate?: DownloadUploadStats & { audio?: DownloadUploadStats; video?: DownloadUploadStats; }; connectionQuality?: number; packetLoss?: { total: number; download: number; upload: number; }; } interface JitsiConnectionQuality { _remoteStats: Record<string, JitsiBridgeStats>; getStats(): JitsiBridgeStats; } interface JitsiStatistics { addConnectionStatsListener(callback: () => void): void; removeConnectionStatsListener(callback: () => void): void; addMediaNotFlowingListener(callback: (track: JitsiRemoteTrack) => void): void; removeMediaNotFlowingListener( callback: (track: JitsiRemoteTrack) => void, ): void; } type JitsiListenable<EventName> = { addListener(eventName: EventName, listener: UntypedCallback): () => void; removeListener(eventName: EventName, listener: UntypedCallback); // Aliases addEventListener: JitsiListenable<EventName>['addListener']; removeEventListener: JitsiListenable<EventName>['removeListener']; on: JitsiListenable<EventName>['addListener']; off: JitsiListenable<EventName>['removeListener']; }; type StropheConnectionHandlerRef = unknown; type JitsiXmppConnection = { getJid(): string; pingDomain: string | undefined | null; ping: { ping( jid: string, success: () => unknown, error: () => unknown, timeout: number, ): void; }; _stropheConn: { _doDisconnect(condition: string): void; _proto: { _abortAllRequests(): void; }; addHandler( handler: (presence: Node) => void, ns: string | null, name: string, type: string | null, id: string | null, from?: string, options?: { matchBare?: boolean }, ): StropheConnectionHandlerRef; deleteHandler(handlerRef: StropheConnectionHandlerRef): void; }; disconnect(reason?: string): void; flush(): void; getXmppLog(): Array<[number, string, string]>; connection: { emuc: { addEventListener(event: string, callback: UntypedCallback): () => void; removeEventListener(event: string, callback: UntypedCallback): void; rooms: Record<string, any>; }; }; }; type JitsiXmppListenable = JitsiListenable<JitsiXmppEventType>; type JitsiXmpp = JitsiXmppListenable & { roomjid: string; myroomjid: string; connection: JitsiXmppConnection; members: Record<string, unknown>; /** @deprecated It doesn't work */ ping(timeout: number): Promise<boolean>; /** Flush presence state */ sendPresence(): void; kick(jid: string, reason?: string): void; lobby?: { lobbyRoom?: Omit<JitsiXmpp, 'lobby'>; }; }; type LobbyRoom = { isSupported: () => boolean; enable: () => Promise<unknown>; disable: () => void; setLobbyRoomJid: (jid: string