@signalwire/core
Advanced tools
Comparing version 3.0.0-beta.1 to 3.0.0-beta.2
@@ -7,2 +7,9 @@ import { BaseClientOptions } from './utils/interfaces'; | ||
/** | ||
* Starts the initialization process as soon as the Client has been | ||
* registered in the Redux store. | ||
* | ||
* @internal | ||
*/ | ||
protected onClientSubscribed(): void; | ||
/** | ||
* Connect the underlay WebSocket connection to the SignalWire network. | ||
@@ -9,0 +16,0 @@ * |
@@ -0,2 +1,4 @@ | ||
import { Action } from '@reduxjs/toolkit'; | ||
import { ExecuteParams, BaseComponentOptions, Emitter } from './utils/interfaces'; | ||
import { EventEmitter } from './utils/EventEmitter'; | ||
import { SDKState } from './redux/interfaces'; | ||
@@ -6,4 +8,9 @@ export declare class BaseComponent implements Emitter { | ||
id: string; | ||
private _eventsRegisterQueue; | ||
private _eventsEmitQueue; | ||
private _eventsNamespace?; | ||
private _requests; | ||
private _customSagaTriggers; | ||
private _destroyer?; | ||
private _getNamespacedEvent; | ||
constructor(options: BaseComponentOptions); | ||
@@ -13,10 +20,44 @@ /** @internal */ | ||
/** @internal */ | ||
get store(): import("redux").Store<any, import("redux").AnyAction>; | ||
get store(): { | ||
runSaga: <S extends import("redux-saga").Saga<any[]>>(saga: S, ...args: Parameters<S>) => import("redux-saga").Task; | ||
dispatch: import("redux-thunk").ThunkDispatch<import("redux").CombinedState<{ | ||
components: Readonly<import("./redux/interfaces").ComponentState>; | ||
session: Readonly<import("./redux/interfaces").SessionState>; | ||
executeQueue: Readonly<import("./redux/interfaces").ExecuteQueueState>; | ||
}>, null, import("redux").AnyAction> & import("redux-thunk").ThunkDispatch<import("redux").CombinedState<{ | ||
components: Readonly<import("./redux/interfaces").ComponentState>; | ||
session: Readonly<import("./redux/interfaces").SessionState>; | ||
executeQueue: Readonly<import("./redux/interfaces").ExecuteQueueState>; | ||
}>, undefined, import("redux").AnyAction> & import("redux").Dispatch<import("redux").AnyAction>; | ||
getState(): import("redux").CombinedState<{ | ||
components: Readonly<import("./redux/interfaces").ComponentState>; | ||
session: Readonly<import("./redux/interfaces").SessionState>; | ||
executeQueue: Readonly<import("./redux/interfaces").ExecuteQueueState>; | ||
}>; | ||
subscribe(listener: () => void): import("redux").Unsubscribe; | ||
replaceReducer(nextReducer: import("redux").Reducer<import("redux").CombinedState<{ | ||
components: Readonly<import("./redux/interfaces").ComponentState>; | ||
session: Readonly<import("./redux/interfaces").SessionState>; | ||
executeQueue: Readonly<import("./redux/interfaces").ExecuteQueueState>; | ||
}>, import("redux").AnyAction>): void; | ||
[Symbol.observable](): import("redux").Observable<import("redux").CombinedState<{ | ||
components: Readonly<import("./redux/interfaces").ComponentState>; | ||
session: Readonly<import("./redux/interfaces").SessionState>; | ||
executeQueue: Readonly<import("./redux/interfaces").ExecuteQueueState>; | ||
}>>; | ||
}; | ||
/** @internal */ | ||
get emitter(): Emitter; | ||
on(...params: Parameters<Emitter['on']>): import("eventemitter3")<string | symbol, any>; | ||
once(...params: Parameters<Emitter['once']>): import("eventemitter3")<string | symbol, any>; | ||
off(...params: Parameters<Emitter['off']>): import("eventemitter3")<string | symbol, any>; | ||
emit(...params: Parameters<Emitter['emit']>): boolean; | ||
removeAllListeners(...params: Parameters<Emitter['removeAllListeners']>): import("eventemitter3")<string | symbol, any>; | ||
/** @internal */ | ||
private addEventToRegisterQueue; | ||
/** @internal */ | ||
private addEventToEmitQueue; | ||
/** @internal */ | ||
private shouldAddToQueue; | ||
on(...params: Parameters<Emitter['on']>): EventEmitter<string | symbol, any>; | ||
once(...params: Parameters<Emitter['once']>): EventEmitter<string | symbol, any>; | ||
off(...params: Parameters<Emitter['off']>): EventEmitter<string | symbol, any>; | ||
removeAllListeners(...params: Parameters<Emitter['removeAllListeners']>): EventEmitter<string | symbol, any>; | ||
eventNames(): (string | symbol)[]; | ||
emit(event: string | symbol, ...args: any[]): boolean; | ||
destroy(): void; | ||
@@ -26,2 +67,10 @@ /** @internal */ | ||
/** @internal */ | ||
triggerCustomSaga<T>(action: Action): Promise<T>; | ||
/** @internal */ | ||
settleCustomSagaTrigger<T>({ dispatchId, payload, kind, }: { | ||
dispatchId: string; | ||
payload?: T; | ||
kind: 'resolve' | 'reject'; | ||
}): void; | ||
/** @internal */ | ||
select<T>(selectorFn: (state: SDKState) => T): T; | ||
@@ -32,3 +81,11 @@ /** @internal */ | ||
onSuccess(component: any): void; | ||
/** @internal */ | ||
private flushEventsRegisterQueue; | ||
/** @internal */ | ||
private flushEventsEmitQueue; | ||
/** @internal */ | ||
private flushEventsQueue; | ||
/** @internal */ | ||
protected _attachListeners(namespace: string): void; | ||
} | ||
//# sourceMappingURL=BaseComponent.d.ts.map |
@@ -1,2 +0,2 @@ | ||
import { uuid, logger } from './utils'; | ||
import { uuid, logger, isGlobalEvent } from './utils'; | ||
import { BaseSession } from './BaseSession'; | ||
@@ -8,3 +8,3 @@ import { BaseJWTSession } from './BaseJWTSession'; | ||
import { EventEmitter, getEventEmitter } from './utils/EventEmitter'; | ||
export { uuid, logger, BaseSession, BaseJWTSession, BaseComponent, BaseClient, connect, configureStore, EventEmitter, getEventEmitter }; | ||
export { uuid, logger, BaseSession, BaseJWTSession, BaseComponent, BaseClient, connect, configureStore, EventEmitter, getEventEmitter, isGlobalEvent }; | ||
export * from './RPCMessages'; | ||
@@ -14,3 +14,5 @@ export * from './utils/interfaces'; | ||
export * from './CustomErrors'; | ||
export type { SessionState } from './redux/interfaces'; | ||
export type { SessionState, CustomSagaParams, CustomSaga, } from './redux/interfaces'; | ||
export * as actions from './redux/actions'; | ||
export * as Rooms from './rooms'; | ||
export declare const selectors: { | ||
@@ -17,0 +19,0 @@ getIceServers: ({ session }: import("./redux/interfaces").SDKState) => RTCIceServer[]; |
@@ -0,1 +1,2 @@ | ||
import { Action } from '@reduxjs/toolkit'; | ||
import { JSONRPCRequest, SessionAuthError } from '../utils/interfaces'; | ||
@@ -5,2 +6,3 @@ import { ExecuteActionParams } from './interfaces'; | ||
export declare const destroyAction: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"swSdk/destroy">; | ||
export declare const closeConnectionAction: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"swSdk/closeConnection">; | ||
/** | ||
@@ -10,12 +12,16 @@ * Trigger saga to send a blade.execute over the wire | ||
export declare const executeAction: import("@reduxjs/toolkit").ActionCreatorWithPayload<ExecuteActionParams, string>; | ||
export declare const authError: import("@reduxjs/toolkit").ActionCreatorWithPayload<{ | ||
export declare const authErrorAction: import("@reduxjs/toolkit").ActionCreatorWithPayload<{ | ||
error: SessionAuthError; | ||
}, string>; | ||
export declare const authSuccess: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"auth/success">; | ||
export declare const socketClosed: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"socket/closed">; | ||
export declare const socketError: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"socket/error">; | ||
export declare const socketMessage: import("@reduxjs/toolkit").ActionCreatorWithPayload<JSONRPCRequest, string>; | ||
export declare const sessionConnected: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"session.unknown" | "session.idle" | "session.reconnecting" | "session.connected" | "session.disconnected">; | ||
export declare const sessionDisconnected: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"session.unknown" | "session.idle" | "session.reconnecting" | "session.connected" | "session.disconnected">; | ||
export declare const sessionReconnecting: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"session.unknown" | "session.idle" | "session.reconnecting" | "session.connected" | "session.disconnected">; | ||
export declare const authSuccessAction: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"auth/success">; | ||
export declare const socketClosedAction: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"socket/closed">; | ||
export declare const socketErrorAction: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"socket/error">; | ||
export declare const socketMessageAction: import("@reduxjs/toolkit").ActionCreatorWithPayload<JSONRPCRequest, string>; | ||
export declare const sessionConnectedAction: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"session.unknown" | "session.idle" | "session.reconnecting" | "session.connected" | "session.disconnected">; | ||
export declare const sessionDisconnectedAction: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"session.unknown" | "session.idle" | "session.reconnecting" | "session.connected" | "session.disconnected">; | ||
export declare const sessionReconnectingAction: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"session.unknown" | "session.idle" | "session.reconnecting" | "session.connected" | "session.disconnected">; | ||
export declare const makeCustomSagaAction: (id: string, action: Action) => { | ||
type: string; | ||
}; | ||
export declare const getCustomSagaActionType: (id: string, action: Action) => string; | ||
//# sourceMappingURL=actions.d.ts.map |
@@ -1,4 +0,3 @@ | ||
import { Store } from 'redux'; | ||
import { ReduxComponent } from './interfaces'; | ||
import { SessionState } from '../redux/interfaces'; | ||
import { ReduxComponent, SessionState, CustomSaga } from './interfaces'; | ||
import { SDKStore } from './'; | ||
declare type ComponentEventHandler = (component: ReduxComponent) => unknown; | ||
@@ -9,4 +8,5 @@ declare type SessionEventHandler = (session: SessionState) => unknown; | ||
sessionListeners?: Partial<Record<ReduxSessionKeys, string | SessionEventHandler>>; | ||
store: Store; | ||
store: SDKStore; | ||
Component: new (o: any) => T; | ||
customSagas?: Array<CustomSaga<T>>; | ||
} | ||
@@ -13,0 +13,0 @@ declare type ReduxSessionKeys = keyof SessionState; |
export * from './component/componentSlice'; | ||
export * from './executeQueue/executeQueueSlice'; | ||
export * from './session/sessionSlice'; | ||
//# sourceMappingURL=index.d.ts.map |
import { PayloadAction } from '@reduxjs/toolkit'; | ||
import { SessionState } from '../../interfaces'; | ||
import { IBladeConnectResult } from '../../../utils/interfaces'; | ||
import { IBladeConnectResult, SessionAuthStatus } from '../../../utils/interfaces'; | ||
export declare const initialSessionState: Readonly<SessionState>; | ||
export declare const sessionActions: import("@reduxjs/toolkit").CaseReducerActions<{ | ||
connected: (state: import("immer/dist/internal").WritableDraft<Readonly<SessionState>>, { payload }: PayloadAction<IBladeConnectResult>) => void; | ||
authStatus: (state: import("immer/dist/internal").WritableDraft<Readonly<SessionState>>, { payload }: PayloadAction<SessionAuthStatus>) => void; | ||
}>, sessionReducer: import("redux").Reducer<Readonly<SessionState>, import("redux").AnyAction>; | ||
//# sourceMappingURL=sessionSlice.d.ts.map |
@@ -10,17 +10,33 @@ import { SDKState } from './interfaces'; | ||
} | ||
declare const configureStore: (options: ConfigureStoreOptions) => import("@reduxjs/toolkit").EnhancedStore<import("redux").CombinedState<{ | ||
components: Readonly<import("./interfaces").ComponentState>; | ||
session: Readonly<import("./interfaces").SessionState>; | ||
}>, import("redux").AnyAction, import("@reduxjs/toolkit").MiddlewareArray<import("redux-thunk").ThunkMiddleware<import("redux").CombinedState<{ | ||
components: Readonly<import("./interfaces").ComponentState>; | ||
session: Readonly<import("./interfaces").SessionState>; | ||
}>, import("redux").AnyAction, null> | import("redux-thunk").ThunkMiddleware<import("redux").CombinedState<{ | ||
components: Readonly<import("./interfaces").ComponentState>; | ||
session: Readonly<import("./interfaces").SessionState>; | ||
}>, import("redux").AnyAction, undefined> | import("redux").Middleware<{}, import("redux").CombinedState<{ | ||
components: Readonly<import("./interfaces").ComponentState>; | ||
session: Readonly<import("./interfaces").SessionState>; | ||
}>, import("redux").Dispatch<import("redux").AnyAction>> | import("redux-saga").SagaMiddleware<object>>>; | ||
export declare type SDKStore = ReturnType<typeof configureStore>; | ||
declare const configureStore: (options: ConfigureStoreOptions) => { | ||
runSaga: <S extends import("redux-saga").Saga<any[]>>(saga: S, ...args: Parameters<S>) => import("redux-saga").Task; | ||
dispatch: import("redux-thunk").ThunkDispatch<import("redux").CombinedState<{ | ||
components: Readonly<import("./interfaces").ComponentState>; | ||
session: Readonly<import("./interfaces").SessionState>; | ||
executeQueue: Readonly<import("./interfaces").ExecuteQueueState>; | ||
}>, null, import("redux").AnyAction> & import("redux-thunk").ThunkDispatch<import("redux").CombinedState<{ | ||
components: Readonly<import("./interfaces").ComponentState>; | ||
session: Readonly<import("./interfaces").SessionState>; | ||
executeQueue: Readonly<import("./interfaces").ExecuteQueueState>; | ||
}>, undefined, import("redux").AnyAction> & import("redux").Dispatch<import("redux").AnyAction>; | ||
getState(): import("redux").CombinedState<{ | ||
components: Readonly<import("./interfaces").ComponentState>; | ||
session: Readonly<import("./interfaces").SessionState>; | ||
executeQueue: Readonly<import("./interfaces").ExecuteQueueState>; | ||
}>; | ||
subscribe(listener: () => void): import("redux").Unsubscribe; | ||
replaceReducer(nextReducer: import("redux").Reducer<import("redux").CombinedState<{ | ||
components: Readonly<import("./interfaces").ComponentState>; | ||
session: Readonly<import("./interfaces").SessionState>; | ||
executeQueue: Readonly<import("./interfaces").ExecuteQueueState>; | ||
}>, import("redux").AnyAction>): void; | ||
[Symbol.observable](): import("redux").Observable<import("redux").CombinedState<{ | ||
components: Readonly<import("./interfaces").ComponentState>; | ||
session: Readonly<import("./interfaces").SessionState>; | ||
executeQueue: Readonly<import("./interfaces").ExecuteQueueState>; | ||
}>>; | ||
}; | ||
export { connect, configureStore }; | ||
export * from './actions'; | ||
//# sourceMappingURL=index.d.ts.map |
import { PayloadAction } from '@reduxjs/toolkit'; | ||
import type { Saga, Task, SagaIterator } from '@redux-saga/types'; | ||
import { JSONRPCResponse, SessionAuthError, SessionAuthStatus, BladeExecuteMethod, BaseConnectionState } from '../utils/interfaces'; | ||
@@ -36,2 +37,3 @@ interface SWComponent { | ||
authError?: SessionAuthError; | ||
authCount: number; | ||
} | ||
@@ -41,2 +43,3 @@ export interface SDKState { | ||
session: SessionState; | ||
executeQueue: ExecuteQueueState; | ||
} | ||
@@ -49,3 +52,11 @@ export interface ExecuteActionParams { | ||
} | ||
export interface ExecuteQueueState { | ||
queue: ExecuteActionParams[]; | ||
} | ||
export interface CustomSagaParams<T> { | ||
instance: T; | ||
runSaga: <S extends Saga>(saga: S, ...args: Parameters<S>) => Task; | ||
} | ||
export declare type CustomSaga<T> = (params: CustomSagaParams<T>) => SagaIterator<any>; | ||
export {}; | ||
//# sourceMappingURL=interfaces.d.ts.map |
export declare const rootReducer: import("redux").Reducer<import("redux").CombinedState<{ | ||
components: Readonly<import("./interfaces").ComponentState>; | ||
session: Readonly<import("./interfaces").SessionState>; | ||
executeQueue: Readonly<import("./interfaces").ExecuteQueueState>; | ||
}>, import("redux").AnyAction>; | ||
//# sourceMappingURL=rootReducer.d.ts.map |
@@ -8,16 +8,32 @@ import { IBladeConnectResult } from './utils/interfaces'; | ||
*/ | ||
export declare const configureJestStore: () => import("@reduxjs/toolkit").EnhancedStore<import("redux").CombinedState<{ | ||
components: Readonly<import("./redux/interfaces").ComponentState>; | ||
session: Readonly<import(".").SessionState>; | ||
}>, import("redux").AnyAction, import("@reduxjs/toolkit").MiddlewareArray<import("redux-thunk").ThunkMiddleware<import("redux").CombinedState<{ | ||
components: Readonly<import("./redux/interfaces").ComponentState>; | ||
session: Readonly<import(".").SessionState>; | ||
}>, import("redux").AnyAction, null> | import("redux-thunk").ThunkMiddleware<import("redux").CombinedState<{ | ||
components: Readonly<import("./redux/interfaces").ComponentState>; | ||
session: Readonly<import(".").SessionState>; | ||
}>, import("redux").AnyAction, undefined> | import("redux").Middleware<{}, import("redux").CombinedState<{ | ||
components: Readonly<import("./redux/interfaces").ComponentState>; | ||
session: Readonly<import(".").SessionState>; | ||
}>, import("redux").Dispatch<import("redux").AnyAction>> | import("redux-saga").SagaMiddleware<object>>>; | ||
export declare const configureJestStore: () => { | ||
runSaga: <S extends import("redux-saga").Saga<any[]>>(saga: S, ...args: Parameters<S>) => import("redux-saga").Task; | ||
dispatch: import("redux-thunk").ThunkDispatch<import("redux").CombinedState<{ | ||
components: Readonly<import("./redux/interfaces").ComponentState>; | ||
session: Readonly<import(".").SessionState>; | ||
executeQueue: Readonly<import("./redux/interfaces").ExecuteQueueState>; | ||
}>, null, import("redux").AnyAction> & import("redux-thunk").ThunkDispatch<import("redux").CombinedState<{ | ||
components: Readonly<import("./redux/interfaces").ComponentState>; | ||
session: Readonly<import(".").SessionState>; | ||
executeQueue: Readonly<import("./redux/interfaces").ExecuteQueueState>; | ||
}>, undefined, import("redux").AnyAction> & import("redux").Dispatch<import("redux").AnyAction>; | ||
getState(): import("redux").CombinedState<{ | ||
components: Readonly<import("./redux/interfaces").ComponentState>; | ||
session: Readonly<import(".").SessionState>; | ||
executeQueue: Readonly<import("./redux/interfaces").ExecuteQueueState>; | ||
}>; | ||
subscribe(listener: () => void): import("redux").Unsubscribe; | ||
replaceReducer(nextReducer: import("redux").Reducer<import("redux").CombinedState<{ | ||
components: Readonly<import("./redux/interfaces").ComponentState>; | ||
session: Readonly<import(".").SessionState>; | ||
executeQueue: Readonly<import("./redux/interfaces").ExecuteQueueState>; | ||
}>, import("redux").AnyAction>): void; | ||
[Symbol.observable](): import("redux").Observable<import("redux").CombinedState<{ | ||
components: Readonly<import("./redux/interfaces").ComponentState>; | ||
session: Readonly<import(".").SessionState>; | ||
executeQueue: Readonly<import("./redux/interfaces").ExecuteQueueState>; | ||
}>>; | ||
}; | ||
export declare const wait: (ms: number) => Promise<unknown>; | ||
export declare const bladeConnectResultVRT: IBladeConnectResult; | ||
//# sourceMappingURL=testUtils.d.ts.map |
@@ -12,2 +12,3 @@ export declare const STORAGE_PREFIX = "@signalwire:"; | ||
} | ||
export declare const GLOBAL_VIDEO_EVENTS: readonly ["room.started", "room.ended"]; | ||
export declare enum BladeMethod { | ||
@@ -14,0 +15,0 @@ Broadcast = "blade.broadcast", |
@@ -10,3 +10,7 @@ import EventEmitter from 'eventemitter3'; | ||
declare const getEventEmitter: <T>(userOptions: UserOptions) => StrictEventEmitter<EventEmitter<string | symbol, any>, T, T, "addEventListener" | "removeEventListener", "on" | "once" | "emit" | "addListener" | "removeListener">; | ||
export { assertEventEmitter, EventEmitter, getEventEmitter }; | ||
declare const getNamespacedEvent: ({ namespace, event, }: { | ||
namespace: string; | ||
event: string; | ||
}) => string; | ||
export { assertEventEmitter, EventEmitter, getEventEmitter, getNamespacedEvent }; | ||
//# sourceMappingURL=EventEmitter.d.ts.map |
@@ -0,1 +1,2 @@ | ||
import { RoomEventNames } from './interfaces'; | ||
export { v4 as uuid } from 'uuid'; | ||
@@ -11,2 +12,4 @@ export { logger } from './logger'; | ||
export declare const timeoutPromise: (promise: Promise<unknown>, time: number, exception: any) => Promise<unknown>; | ||
export declare const isGlobalEvent: (event: RoomEventNames) => boolean; | ||
export declare const getGlobalEvents: (kind?: 'all' | 'video') => readonly ["room.started", "room.ended"] | ("room.ended" | "room.started")[]; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -1,8 +0,9 @@ | ||
import { Store } from 'redux'; | ||
import type { EventEmitter } from '../utils/EventEmitter'; | ||
import { BaseSession } from '../BaseSession'; | ||
import { SDKStore } from '../redux'; | ||
import { GLOBAL_VIDEO_EVENTS } from './constants'; | ||
/** | ||
* Minimal interface the emitter must fulfill | ||
*/ | ||
export declare type Emitter = Pick<EventEmitter, 'on' | 'off' | 'once' | 'emit' | 'removeAllListeners'>; | ||
export declare type Emitter = Pick<EventEmitter, 'on' | 'off' | 'once' | 'emit' | 'removeAllListeners' | 'eventNames'>; | ||
declare type JSONRPCParams = { | ||
@@ -45,7 +46,7 @@ [key: string]: any; | ||
export interface BaseClientOptions extends UserOptions { | ||
store: Store; | ||
store: SDKStore; | ||
emitter: Emitter; | ||
} | ||
export interface BaseComponentOptions { | ||
store: Store; | ||
store: SDKStore; | ||
emitter: Emitter; | ||
@@ -137,10 +138,9 @@ } | ||
} | ||
declare type RoomMemberType = 'member' | 'screen'; | ||
declare type RoomMemberType = 'member' | 'screen' | 'device'; | ||
interface RoomMemberCommon { | ||
id: string; | ||
room_session_id: string; | ||
room_id: string; | ||
} | ||
interface RoomMemberProperties { | ||
scope_id: string; | ||
parent_id?: string; | ||
input_volume: number; | ||
@@ -246,2 +246,6 @@ input_sensitivity: number; | ||
/** | ||
* List of all room members | ||
*/ | ||
declare type RoomMembersMethod = 'members.get'; | ||
/** | ||
* List of all room member methods | ||
@@ -257,3 +261,3 @@ */ | ||
*/ | ||
export declare type RoomMethod = 'video.list_available_layouts' | 'video.hide_video_muted' | 'video.show_video_muted' | `video.${RoomMemberMethod}` | `video.${RoomLayoutMethod}`; | ||
export declare type RoomMethod = 'video.list_available_layouts' | 'video.hide_video_muted' | 'video.show_video_muted' | `video.${RoomMembersMethod}` | `video.${RoomMemberMethod}` | `video.${RoomLayoutMethod}`; | ||
/** | ||
@@ -276,3 +280,7 @@ * List of all available blade.execute methods | ||
}; | ||
export declare type GlobalVideoEvents = typeof GLOBAL_VIDEO_EVENTS[number]; | ||
export declare type RoomCustomMethods<T> = { | ||
[k in keyof T]: PropertyDescriptor; | ||
}; | ||
export {}; | ||
//# sourceMappingURL=interfaces.d.ts.map |
@@ -6,3 +6,3 @@ { | ||
"license": "MIT", | ||
"version": "3.0.0-beta.1", | ||
"version": "3.0.0-beta.2", | ||
"source": "src/index.ts", | ||
@@ -9,0 +9,0 @@ "main": "dist/index.js", |
@@ -12,2 +12,12 @@ import { AuthError } from './CustomErrors' | ||
/** | ||
* Starts the initialization process as soon as the Client has been | ||
* registered in the Redux store. | ||
* | ||
* @internal | ||
*/ | ||
protected onClientSubscribed() { | ||
this._attachListeners('') | ||
} | ||
/** | ||
* Connect the underlay WebSocket connection to the SignalWire network. | ||
@@ -27,3 +37,3 @@ * | ||
const error = authError | ||
? new AuthError(authError.code, authError.message) | ||
? new AuthError(authError.code, authError.error) | ||
: new Error('Unauthorized') | ||
@@ -30,0 +40,0 @@ reject(error) |
@@ -1,2 +0,3 @@ | ||
import { uuid } from './utils' | ||
import { Action } from '@reduxjs/toolkit' | ||
import { uuid, logger, getGlobalEvents } from './utils' | ||
import { executeAction } from './redux' | ||
@@ -8,10 +9,43 @@ import { | ||
} from './utils/interfaces' | ||
import { EventEmitter, getNamespacedEvent } from './utils/EventEmitter' | ||
import { SDKState } from './redux/interfaces' | ||
import { makeCustomSagaAction } from './redux/actions' | ||
type EventRegisterHandlers = | ||
| { | ||
type: 'on' | ||
params: Parameters<Emitter['on']> | ||
} | ||
| { | ||
type: 'off' | ||
params: Parameters<Emitter['off']> | ||
} | ||
| { | ||
type: 'once' | ||
params: Parameters<Emitter['once']> | ||
} | ||
| { | ||
type: 'removeAllListeners' | ||
params: Parameters<Emitter['removeAllListeners']> | ||
} | ||
export class BaseComponent implements Emitter { | ||
id = uuid() | ||
private _eventsRegisterQueue = new Set<EventRegisterHandlers>() | ||
private _eventsEmitQueue = new Set<any>() | ||
private _eventsNamespace?: string | ||
private _requests = new Map() | ||
private _customSagaTriggers = new Map() | ||
private _destroyer?: () => void | ||
private _getNamespacedEvent(event: string | symbol) { | ||
if (typeof event === 'string' && this._eventsNamespace !== undefined) { | ||
return getNamespacedEvent({ | ||
namespace: this._eventsNamespace, | ||
event, | ||
}) | ||
} | ||
return event | ||
} | ||
constructor(public options: BaseComponentOptions) {} | ||
@@ -34,22 +68,110 @@ | ||
/** @internal */ | ||
private addEventToRegisterQueue(options: EventRegisterHandlers) { | ||
const [event, fn, context] = options.params | ||
logger.debug('Adding event to the register queue', { event, fn, context }) | ||
// @ts-ignore | ||
this._eventsRegisterQueue.add({ | ||
type: options.type, | ||
params: options.params, | ||
}) | ||
return this.emitter as EventEmitter<string | symbol, any> | ||
} | ||
/** @internal */ | ||
private addEventToEmitQueue(event: string | symbol, args: any[]) { | ||
logger.debug('Adding to the emit queue', event) | ||
this._eventsEmitQueue.add({ event, args }) | ||
} | ||
/** @internal */ | ||
private shouldAddToQueue() { | ||
return this._eventsNamespace === undefined | ||
} | ||
on(...params: Parameters<Emitter['on']>) { | ||
return this.emitter.on(...params) | ||
if (this.shouldAddToQueue()) { | ||
this.addEventToRegisterQueue({ type: 'on', params }) | ||
return this.emitter as EventEmitter<string | symbol, any> | ||
} | ||
const [event, fn, context] = params | ||
const namespacedEvent = this._getNamespacedEvent(event) | ||
logger.debug('Registering event', namespacedEvent) | ||
return this.emitter.on(namespacedEvent, fn, context) | ||
} | ||
once(...params: Parameters<Emitter['once']>) { | ||
return this.emitter.once(...params) | ||
if (this.shouldAddToQueue()) { | ||
this.addEventToRegisterQueue({ type: 'once', params }) | ||
return this.emitter as EventEmitter<string | symbol, any> | ||
} | ||
const [event, fn, context] = params | ||
const namespacedEvent = this._getNamespacedEvent(event) | ||
logger.debug('Registering event', namespacedEvent) | ||
return this.emitter.once(namespacedEvent, fn, context) | ||
} | ||
off(...params: Parameters<Emitter['off']>) { | ||
return this.emitter.off(...params) | ||
} | ||
if (this.shouldAddToQueue()) { | ||
this.addEventToRegisterQueue({ type: 'off', params }) | ||
return this.emitter as EventEmitter<string | symbol, any> | ||
} | ||
emit(...params: Parameters<Emitter['emit']>) { | ||
return this.emitter.emit(...params) | ||
const [event, fn, context, once] = params | ||
const namespacedEvent = this._getNamespacedEvent(event) | ||
logger.debug('Registering event', namespacedEvent) | ||
return this.emitter.off(namespacedEvent, fn, context, once) | ||
} | ||
removeAllListeners(...params: Parameters<Emitter['removeAllListeners']>) { | ||
return this.emitter.removeAllListeners(...params) | ||
if (this.shouldAddToQueue()) { | ||
this.addEventToRegisterQueue({ type: 'removeAllListeners', params }) | ||
return this.emitter as EventEmitter<string | symbol, any> | ||
} | ||
const [event] = params | ||
if (event) { | ||
return this.emitter.removeAllListeners(this._getNamespacedEvent(event)) | ||
} | ||
if (this._eventsNamespace !== undefined) { | ||
this.eventNames().forEach((event) => { | ||
if ( | ||
typeof event === 'string' && | ||
event.startsWith(this._eventsNamespace!) | ||
) { | ||
this.emitter.removeAllListeners(event) | ||
} else if (typeof event === 'symbol') { | ||
logger.warn( | ||
'Remove events registered using `symbol` is not supported.' | ||
) | ||
} | ||
}) | ||
} else { | ||
logger.debug('Removing global events only.') | ||
getGlobalEvents().forEach((event) => { | ||
this.emitter.removeAllListeners(event) | ||
}) | ||
} | ||
return this.emitter as EventEmitter<string | symbol, any> | ||
} | ||
eventNames() { | ||
return this.emitter.eventNames() | ||
} | ||
emit(event: string | symbol, ...args: any[]) { | ||
if (this.shouldAddToQueue()) { | ||
this.addEventToEmitQueue(event, args) | ||
return false | ||
} | ||
const namespacedEvent = this._getNamespacedEvent(event) | ||
logger.debug('Adding to the emit queue', namespacedEvent) | ||
return this.emitter.emit(namespacedEvent, ...args) | ||
} | ||
destroy() { | ||
@@ -78,2 +200,32 @@ this._destroyer?.() | ||
/** @internal */ | ||
triggerCustomSaga<T>(action: Action): Promise<T> { | ||
return new Promise((resolve, reject) => { | ||
const dispatchId = uuid() | ||
this._customSagaTriggers.set(dispatchId, { resolve, reject }) | ||
this.store.dispatch({ | ||
dispatchId, | ||
...makeCustomSagaAction(this.id, action), | ||
}) | ||
}) | ||
} | ||
/** @internal */ | ||
settleCustomSagaTrigger<T>({ | ||
dispatchId, | ||
payload, | ||
kind, | ||
}: { | ||
dispatchId: string | ||
payload?: T | ||
kind: 'resolve' | 'reject' | ||
}) { | ||
const actions = this._customSagaTriggers.get(dispatchId) | ||
if (actions) { | ||
actions[kind](payload) | ||
this._customSagaTriggers.delete(dispatchId) | ||
} | ||
} | ||
/** @internal */ | ||
select<T>(selectorFn: (state: SDKState) => T) { | ||
@@ -98,2 +250,36 @@ return selectorFn(this.store.getState()) | ||
} | ||
/** @internal */ | ||
private flushEventsRegisterQueue() { | ||
this._eventsRegisterQueue.forEach((item) => { | ||
// @ts-ignore | ||
this[item.type](...item.params) | ||
this._eventsRegisterQueue.delete(item) | ||
}) | ||
} | ||
/** @internal */ | ||
private flushEventsEmitQueue() { | ||
this._eventsEmitQueue.forEach((item) => { | ||
const { event, args } = item | ||
this.emit(event, ...args) | ||
this._eventsEmitQueue.delete(item) | ||
}) | ||
} | ||
/** @internal */ | ||
private flushEventsQueue() { | ||
this.flushEventsRegisterQueue() | ||
this.flushEventsEmitQueue() | ||
} | ||
/** @internal */ | ||
protected _attachListeners(namespace: string) { | ||
if (namespace === undefined) { | ||
logger.error('Tried to call `_attachListeners` without a `namespace`.') | ||
return | ||
} | ||
this._eventsNamespace = namespace | ||
this.flushEventsQueue() | ||
} | ||
} |
import WS from 'jest-websocket-mock' | ||
import { BaseSession } from './BaseSession' | ||
import { socketMessage } from './redux/actions' | ||
import { socketMessageAction } from './redux/actions' | ||
import { | ||
@@ -11,2 +11,3 @@ BladeConnect, | ||
} from './RPCMessages' | ||
import { wait } from './testUtils' | ||
@@ -101,3 +102,3 @@ jest.mock('uuid', () => { | ||
expect(session.dispatch).toHaveBeenCalledTimes(1) | ||
expect(session.dispatch).toHaveBeenCalledWith(socketMessage(request)) | ||
expect(session.dispatch).toHaveBeenCalledWith(socketMessageAction(request)) | ||
}) | ||
@@ -120,3 +121,3 @@ | ||
it('should close the connection if no blade.ping comes within _checkPingDelay', async (done) => { | ||
it('should close the connection if no blade.ping comes within _checkPingDelay', async () => { | ||
// Force _checkPingDelay to 5ms | ||
@@ -133,9 +134,7 @@ session['_checkPingDelay'] = 5 | ||
// Expect the session to be closed after 10ms | ||
setTimeout(() => { | ||
expect(session.connected).toBe(false) | ||
expect(session.closed).toBe(true) | ||
done() | ||
}, 10) | ||
await wait(10) | ||
expect(session.connected).toBe(false) | ||
expect(session.closed).toBe(true) | ||
}) | ||
}) | ||
}) |
@@ -29,8 +29,10 @@ import { PayloadAction } from '@reduxjs/toolkit' | ||
import { | ||
authError, | ||
authSuccess, | ||
socketClosed, | ||
socketError, | ||
socketMessage, | ||
closeConnectionAction, | ||
authErrorAction, | ||
authSuccessAction, | ||
socketClosedAction, | ||
socketErrorAction, | ||
socketMessageAction, | ||
} from './redux/actions' | ||
import { sessionActions } from './redux/features/session/sessionSlice' | ||
@@ -215,6 +217,6 @@ export class BaseSession { | ||
this._status = 'connected' | ||
this.dispatch(authSuccess()) | ||
this.dispatch(authSuccessAction()) | ||
} catch (error) { | ||
logger.error('Auth Error', error) | ||
this.dispatch(authError({ error })) | ||
this.dispatch(authErrorAction({ error })) | ||
} | ||
@@ -225,3 +227,3 @@ } | ||
logger.debug('_onSocketError', event) | ||
this.dispatch(socketError()) | ||
this.dispatch(socketErrorAction()) | ||
} | ||
@@ -233,3 +235,3 @@ | ||
event.code >= 1006 && event.code <= 1014 ? 'reconnecting' : 'disconnected' | ||
this.dispatch(socketClosed()) | ||
this.dispatch(socketClosedAction()) | ||
this._socket = null | ||
@@ -271,3 +273,3 @@ } | ||
// If it's not a response, trigger the dispatch. | ||
this.dispatch(socketMessage(payload)) | ||
this.dispatch(socketMessageAction(payload)) | ||
} | ||
@@ -318,2 +320,4 @@ } | ||
this._status = status | ||
this.dispatch(sessionActions.authStatus('unknown')) | ||
this.dispatch(closeConnectionAction()) | ||
if (this._socket) { | ||
@@ -320,0 +324,0 @@ this._socket.close() |
@@ -1,2 +0,2 @@ | ||
import { uuid, logger } from './utils' | ||
import { uuid, logger, isGlobalEvent } from './utils' | ||
import { BaseSession } from './BaseSession' | ||
@@ -21,3 +21,4 @@ import { BaseJWTSession } from './BaseJWTSession' | ||
EventEmitter, | ||
getEventEmitter | ||
getEventEmitter, | ||
isGlobalEvent | ||
} | ||
@@ -29,6 +30,11 @@ | ||
export * from './CustomErrors' | ||
export type { SessionState } from './redux/interfaces' | ||
export type { | ||
SessionState, | ||
CustomSagaParams, | ||
CustomSaga, | ||
} from './redux/interfaces' | ||
export * as actions from './redux/actions' | ||
export * as Rooms from './rooms' | ||
export const selectors = { | ||
...sessionSelectors, | ||
} |
@@ -1,2 +0,2 @@ | ||
import { createAction } from '@reduxjs/toolkit' | ||
import { createAction, Action } from '@reduxjs/toolkit' | ||
import { | ||
@@ -11,2 +11,3 @@ JSONRPCRequest, | ||
export const destroyAction = createAction('swSdk/destroy') | ||
export const closeConnectionAction = createAction('swSdk/closeConnection') | ||
@@ -20,8 +21,10 @@ /** | ||
export const authError = createAction<{ error: SessionAuthError }>('auth/error') | ||
export const authSuccess = createAction('auth/success') | ||
export const authErrorAction = createAction<{ error: SessionAuthError }>( | ||
'auth/error' | ||
) | ||
export const authSuccessAction = createAction('auth/success') | ||
export const socketClosed = createAction('socket/closed') | ||
export const socketError = createAction('socket/error') | ||
export const socketMessage = createAction<JSONRPCRequest, string>( | ||
export const socketClosedAction = createAction('socket/closed') | ||
export const socketErrorAction = createAction('socket/error') | ||
export const socketMessageAction = createAction<JSONRPCRequest, string>( | ||
'socket/message' | ||
@@ -31,10 +34,25 @@ ) | ||
// TODO: define if we need/want to send a payload with these events. | ||
export const sessionConnected = createAction<void, SessionEvents>( | ||
export const sessionConnectedAction = createAction<void, SessionEvents>( | ||
'session.connected' | ||
) | ||
export const sessionDisconnected = createAction<void, SessionEvents>( | ||
export const sessionDisconnectedAction = createAction<void, SessionEvents>( | ||
'session.disconnected' | ||
) | ||
export const sessionReconnecting = createAction<void, SessionEvents>( | ||
export const sessionReconnectingAction = createAction<void, SessionEvents>( | ||
'session.reconnecting' | ||
) | ||
const formatCustomSagaAction = (id: string, action: Action) => { | ||
return `${action.type}/${id}` | ||
} | ||
export const makeCustomSagaAction = (id: string, action: Action) => { | ||
return { | ||
...action, | ||
type: formatCustomSagaAction(id, action), | ||
} | ||
} | ||
export const getCustomSagaActionType = (id: string, action: Action) => { | ||
return formatCustomSagaAction(id, action) | ||
} |
@@ -1,7 +0,6 @@ | ||
import { Store } from 'redux' | ||
import { ReduxComponent } from './interfaces' | ||
import { ReduxComponent, SessionState, CustomSaga } from './interfaces' | ||
import { SDKStore } from './' | ||
import { componentActions } from './features' | ||
import { getComponent } from './features/component/componentSelectors' | ||
import { getSession } from './features/session/sessionSelectors' | ||
import { SessionState } from '../redux/interfaces' | ||
@@ -15,4 +14,5 @@ type ComponentEventHandler = (component: ReduxComponent) => unknown | ||
> | ||
store: Store | ||
store: SDKStore | ||
Component: new (o: any) => T | ||
customSagas?: Array<CustomSaga<T>> | ||
} | ||
@@ -30,2 +30,3 @@ type ReduxComponentKeys = keyof ReduxComponent | ||
Component, | ||
customSagas = [], | ||
} = options | ||
@@ -85,5 +86,15 @@ const componentKeys = Object.keys(componentListeners) as ReduxComponentKeys[] | ||
// Run all the custom sagas | ||
const taskList = customSagas?.map((saga) => { | ||
return store.runSaga(saga, { instance, runSaga: store.runSaga }) | ||
}) | ||
instance.destroyer = () => { | ||
storeUnsubscribe() | ||
cacheMap.clear() | ||
// Cancel all the custom sagas | ||
if (taskList?.length) { | ||
taskList.forEach((task) => task.cancel()) | ||
} | ||
} | ||
@@ -90,0 +101,0 @@ |
@@ -1,5 +0,5 @@ | ||
import { createSlice, PayloadAction } from '@reduxjs/toolkit' | ||
import { PayloadAction } from '@reduxjs/toolkit' | ||
import { JSONRPCResponse } from '../../../utils/interfaces' | ||
import { ComponentState, ReduxComponent } from '../../interfaces' | ||
import { destroyAction } from '../../actions' | ||
import { createDestroyableSlice } from '../../utils/createDestroyableSlice' | ||
@@ -24,3 +24,3 @@ export const initialComponentState: Readonly<ComponentState> = { | ||
const componentSlice = createSlice({ | ||
const componentSlice = createDestroyableSlice({ | ||
name: 'components', | ||
@@ -60,7 +60,2 @@ initialState: initialComponentState, | ||
}, | ||
extraReducers: (builder) => { | ||
builder.addCase(destroyAction.type, () => { | ||
return initialComponentState | ||
}) | ||
}, | ||
}) | ||
@@ -67,0 +62,0 @@ |
export * from './component/componentSlice' | ||
export * from './executeQueue/executeQueueSlice' | ||
export * from './session/sessionSlice' |
import { take } from 'redux-saga/effects' | ||
import { logger } from '../../../utils' | ||
import { logger, isGlobalEvent } from '../../../utils' | ||
import { getNamespacedEvent } from '../../../utils/EventEmitter' | ||
const findNamespaceInPayload = (payload?: any): string => { | ||
/** | ||
* TODO: We should check the event type here | ||
* At the moment we handle `room_session_id` only | ||
* but in the future we'll have more APIs (chat/calling/messagging etc.) | ||
*/ | ||
const ns = payload?.room?.room_session_id || payload?.room_session_id | ||
return ns || '' | ||
} | ||
export function* pubSubSaga({ pubSubChannel, emitter }: any) { | ||
@@ -8,3 +20,22 @@ while (true) { | ||
try { | ||
emitter.emit(type, payload) | ||
const namespace = findNamespaceInPayload(payload) | ||
/** | ||
* There are events (like `room.started`/`room.ended`) that can | ||
* be consumed from different places, like from a `roomObj` | ||
* (namespaced Event Emitter) or from a `client` | ||
* (non-namespaced/global Event Emitter) so we must trigger the | ||
* event twice to reach everyone. | ||
*/ | ||
if (isGlobalEvent(type)) { | ||
emitter.emit(type, payload) | ||
} | ||
emitter.emit( | ||
getNamespacedEvent({ | ||
namespace, | ||
event: type, | ||
}), | ||
payload | ||
) | ||
} catch (error) { | ||
@@ -11,0 +42,0 @@ logger.error(error) |
@@ -5,3 +5,3 @@ import { channel, eventChannel } from 'redux-saga' | ||
import { VertoMethod } from '../../../utils/constants' | ||
import { socketMessage, executeAction } from '../../actions' | ||
import { socketMessageAction, executeAction } from '../../actions' | ||
import { componentActions } from '../' | ||
@@ -14,3 +14,3 @@ import { sessionChannelWatcher, createSessionChannel } from './sessionSaga' | ||
const jsonrpc = JSON.parse( | ||
'{"jsonrpc":"2.0","id":"ddcd9807-0339-4a39-92b1-ab7967b84782","method":"blade.broadcast","params":{"broadcaster_nodeid":"2286cac8-1346-474f-9913-7ca9c3df9fc8@west-us","protocol":"signalwire_0d8d431757079b56923f7a2acc25ef69e3f698dd36689ca472cf6bc0fd900426_830b7622-b03b-4a11-9109-19bf2c9e27cf_78429ef1-283b-4fa9-8ebc-16b59f95bb1f","channel":"notifications","event":"conference","params":{"params":{"room":{"room_session_id":"6fbe4472-e6dd-431f-887f-33171cd83ccb","name":"roomName","members":[{"visible":false,"room_session_id":"6fbe4472-e6dd-431f-887f-33171cd83ccb","id":"0e5f67e0-8dbf-48dd-b920-804b97fccee6","audio_muted":false,"name":"Edo","location":{"y":0,"x":0,"layer_index":0,"height":360,"z_index":0,"width":640},"video_muted":false,"room_id":"790d6c79-f0d1-421e-b5f2-f09bd05941ce","type":"member"}],"locked":false,"layouts":[{"id":"group:grid"}],"room_id":"790d6c79-f0d1-421e-b5f2-f09bd05941ce","current_layout":{"id":"1x1","layers":[{"y":0,"x":0,"layer_index":0,"height":720,"z_index":0,"width":1280}],"name":"Full Screen"}},"call_id":"0e5f67e0-8dbf-48dd-b920-804b97fccee6","member_id":"0e5f67e0-8dbf-48dd-b920-804b97fccee6"},"timestamp":"1620991212.326279","event_type":"room.subscribed","event_channel":"room.adaacbef-3d34-4a5f-a123-d3d166515ba0"}},"hops":[]}' | ||
'{"jsonrpc":"2.0","id":"ddcd9807-0339-4a39-92b1-ab7967b84782","method":"blade.broadcast","params":{"broadcaster_nodeid":"2286cac8-1346-474f-9913-7ca9c3df9fc8@west-us","protocol":"signalwire_0d8d431757079b56923f7a2acc25ef69e3f698dd36689ca472cf6bc0fd900426_830b7622-b03b-4a11-9109-19bf2c9e27cf_78429ef1-283b-4fa9-8ebc-16b59f95bb1f","channel":"notifications","event":"conference","params":{"params":{"room":{"room_session_id":"6fbe4472-e6dd-431f-887f-33171cd83ccb","name":"roomName","members":[{"visible":false,"id":"0e5f67e0-8dbf-48dd-b920-804b97fccee6","audio_muted":false,"name":"Edo","video_muted":false,"type":"member"}],"locked":false,"layouts":[{"id":"group:grid"}],"room_id":"790d6c79-f0d1-421e-b5f2-f09bd05941ce","current_layout":{"id":"1x1","layers":[{"y":0,"x":0,"layer_index":0,"height":720,"z_index":0,"width":1280}],"name":"Full Screen"}},"call_id":"0e5f67e0-8dbf-48dd-b920-804b97fccee6","member_id":"0e5f67e0-8dbf-48dd-b920-804b97fccee6"},"timestamp":"1620991212.326279","event_type":"room.subscribed","event_channel":"room.adaacbef-3d34-4a5f-a123-d3d166515ba0"}},"hops":[]}' | ||
) | ||
@@ -35,3 +35,3 @@ let runSaga = true | ||
runSaga = false | ||
return socketMessage(jsonrpc) | ||
return socketMessageAction(jsonrpc) | ||
} else if (runSaga === false) { | ||
@@ -73,3 +73,3 @@ sessionChannel.close() | ||
const jsonrpc = JSON.parse( | ||
'{"jsonrpc":"2.0","id":"02f22650-8601-4e7d-bd1d-d084e69f22b0","method":"blade.broadcast","params":{"broadcaster_nodeid":"2286cac8-1346-474f-9913-7ca9c3df9fc8@west-us","protocol":"signalwire_0d8d431757079b56923f7a2acc25ef69e3f698dd36689ca472cf6bc0fd900426_2e393a80-fafe-4d73-9553-85bbf16b3a89_78429ef1-283b-4fa9-8ebc-16b59f95bb1f","channel":"notifications","event":"conference","params":{"params":{"member":{"updated":["video_muted","visible"],"room_session_id":"4bb14f10-1ed6-44a5-a286-4da86f34738d","id":"ab42641c-e784-42f1-9815-d264105bc24f","visible":true,"room_id":"790d6c79-f0d1-421e-b5f2-f09bd05941ce","video_muted":false}},"timestamp":"1620984182.577089","event_type":"member.updated","event_channel":"room.e1c5fc18-f96d-4696-bf9b-bcb2eab57906"}},"hops":[]}' | ||
'{"jsonrpc":"2.0","id":"02f22650-8601-4e7d-bd1d-d084e69f22b0","method":"blade.broadcast","params":{"broadcaster_nodeid":"2286cac8-1346-474f-9913-7ca9c3df9fc8@west-us","protocol":"signalwire_0d8d431757079b56923f7a2acc25ef69e3f698dd36689ca472cf6bc0fd900426_2e393a80-fafe-4d73-9553-85bbf16b3a89_78429ef1-283b-4fa9-8ebc-16b59f95bb1f","channel":"notifications","event":"conference","params":{"params":{"member":{"updated":["video_muted","visible"],"id":"ab42641c-e784-42f1-9815-d264105bc24f","visible":true,"video_muted":false}},"timestamp":"1620984182.577089","event_type":"member.updated","event_channel":"room.e1c5fc18-f96d-4696-bf9b-bcb2eab57906"}},"hops":[]}' | ||
) | ||
@@ -84,3 +84,3 @@ let runSaga = true | ||
const payload = JSON.parse( | ||
'{"member":{"updated":["video_muted","visible"],"room_session_id":"4bb14f10-1ed6-44a5-a286-4da86f34738d","id":"ab42641c-e784-42f1-9815-d264105bc24f","visible":true,"room_id":"790d6c79-f0d1-421e-b5f2-f09bd05941ce","video_muted":false}}' | ||
'{"member":{"updated":["video_muted","visible"],"id":"ab42641c-e784-42f1-9815-d264105bc24f","visible":true,"video_muted":false}}' | ||
) | ||
@@ -98,3 +98,3 @@ | ||
runSaga = false | ||
return socketMessage(jsonrpc) | ||
return socketMessageAction(jsonrpc) | ||
} else if (runSaga === false) { | ||
@@ -132,3 +132,3 @@ sessionChannel.close() | ||
const jsonrpc = JSON.parse( | ||
'{"jsonrpc":"2.0","id":"6d0e46b2-77af-4734-8691-866f09b37ff3","method":"blade.broadcast","params":{"broadcaster_nodeid":"6a088ac7-9c9b-48c2-a5a1-92aafb70b0ab@west-us","protocol":"signalwire_519264e7f1beedc770d250eabcf50c4ae3bc197dccb6886ed1677ddb4bce8518_b0f0c4e0-e5cb-4ee8-befa-f246ea69b54e_78429ef1-283b-4fa9-8ebc-16b59f95bb1f","channel":"notifications","event":"conference","params":{"params":{"member":{"id":"a3693340-6f42-4cab-b18e-8e2a22695698","room_session_id":"024d3ab2-c444-4f03-8d71-9f43f6f4c78f","room_id":"6e83849b-5cc2-4fc6-80ed-448113c8a426","talking":true}},"timestamp":1624014381.1524,"event_type":"member.talking","event_channel":"room.b0e1b577-f5e7-4337-b7c4-06fa993b1a19"}},"hops":[]}' | ||
'{"jsonrpc":"2.0","id":"6d0e46b2-77af-4734-8691-866f09b37ff3","method":"blade.broadcast","params":{"broadcaster_nodeid":"6a088ac7-9c9b-48c2-a5a1-92aafb70b0ab@west-us","protocol":"signalwire_519264e7f1beedc770d250eabcf50c4ae3bc197dccb6886ed1677ddb4bce8518_b0f0c4e0-e5cb-4ee8-befa-f246ea69b54e_78429ef1-283b-4fa9-8ebc-16b59f95bb1f","channel":"notifications","event":"conference","params":{"params":{"member":{"id":"a3693340-6f42-4cab-b18e-8e2a22695698","talking":true}},"timestamp":1624014381.1524,"event_type":"member.talking","event_channel":"room.b0e1b577-f5e7-4337-b7c4-06fa993b1a19"}},"hops":[]}' | ||
) | ||
@@ -143,3 +143,3 @@ let runSaga = true | ||
const payload = JSON.parse( | ||
'{"member":{"id":"a3693340-6f42-4cab-b18e-8e2a22695698","room_session_id":"024d3ab2-c444-4f03-8d71-9f43f6f4c78f","room_id":"6e83849b-5cc2-4fc6-80ed-448113c8a426","talking":true}}' | ||
'{"member":{"id":"a3693340-6f42-4cab-b18e-8e2a22695698","talking":true}}' | ||
) | ||
@@ -157,3 +157,3 @@ | ||
runSaga = false | ||
return socketMessage(jsonrpc) | ||
return socketMessageAction(jsonrpc) | ||
} else if (runSaga === false) { | ||
@@ -187,3 +187,3 @@ sessionChannel.close() | ||
const jsonrpc = JSON.parse( | ||
'{"jsonrpc":"2.0","id":"6d0e46b2-77af-4734-8691-866f09b37ff3","method":"blade.broadcast","params":{"broadcaster_nodeid":"6a088ac7-9c9b-48c2-a5a1-92aafb70b0ab@west-us","protocol":"signalwire_519264e7f1beedc770d250eabcf50c4ae3bc197dccb6886ed1677ddb4bce8518_b0f0c4e0-e5cb-4ee8-befa-f246ea69b54e_78429ef1-283b-4fa9-8ebc-16b59f95bb1f","channel":"notifications","event":"conference","params":{"params":{"member":{"id":"a3693340-6f42-4cab-b18e-8e2a22695698","room_session_id":"024d3ab2-c444-4f03-8d71-9f43f6f4c78f","room_id":"6e83849b-5cc2-4fc6-80ed-448113c8a426","talking":false}},"timestamp":1624014381.1524,"event_type":"member.talking","event_channel":"room.b0e1b577-f5e7-4337-b7c4-06fa993b1a19"}},"hops":[]}' | ||
'{"jsonrpc":"2.0","id":"6d0e46b2-77af-4734-8691-866f09b37ff3","method":"blade.broadcast","params":{"broadcaster_nodeid":"6a088ac7-9c9b-48c2-a5a1-92aafb70b0ab@west-us","protocol":"signalwire_519264e7f1beedc770d250eabcf50c4ae3bc197dccb6886ed1677ddb4bce8518_b0f0c4e0-e5cb-4ee8-befa-f246ea69b54e_78429ef1-283b-4fa9-8ebc-16b59f95bb1f","channel":"notifications","event":"conference","params":{"params":{"member":{"id":"a3693340-6f42-4cab-b18e-8e2a22695698","talking":false}},"timestamp":1624014381.1524,"event_type":"member.talking","event_channel":"room.b0e1b577-f5e7-4337-b7c4-06fa993b1a19"}},"hops":[]}' | ||
) | ||
@@ -198,3 +198,3 @@ let runSaga = true | ||
const payload = JSON.parse( | ||
'{"member":{"id":"a3693340-6f42-4cab-b18e-8e2a22695698","room_session_id":"024d3ab2-c444-4f03-8d71-9f43f6f4c78f","room_id":"6e83849b-5cc2-4fc6-80ed-448113c8a426","talking":false}}' | ||
'{"member":{"id":"a3693340-6f42-4cab-b18e-8e2a22695698","talking":false}}' | ||
) | ||
@@ -212,3 +212,3 @@ | ||
runSaga = false | ||
return socketMessage(jsonrpc) | ||
return socketMessageAction(jsonrpc) | ||
} else if (runSaga === false) { | ||
@@ -262,3 +262,3 @@ sessionChannel.close() | ||
runSaga = false | ||
return socketMessage(jsonrpc) | ||
return socketMessageAction(jsonrpc) | ||
} else if (runSaga === false) { | ||
@@ -311,3 +311,3 @@ sessionChannel.close() | ||
runSaga = false | ||
return socketMessage(jsonrpc) | ||
return socketMessageAction(jsonrpc) | ||
} | ||
@@ -371,3 +371,3 @@ sessionChannel.close() | ||
runSaga = false | ||
return socketMessage(jsonrpc) | ||
return socketMessageAction(jsonrpc) | ||
} | ||
@@ -428,3 +428,3 @@ sessionChannel.close() | ||
runSaga = false | ||
return socketMessage(jsonrpc) | ||
return socketMessageAction(jsonrpc) | ||
} | ||
@@ -488,3 +488,3 @@ sessionChannel.close() | ||
runSaga = false | ||
return socketMessage(jsonrpc) | ||
return socketMessageAction(jsonrpc) | ||
} | ||
@@ -550,3 +550,3 @@ sessionChannel.close() | ||
runSaga = false | ||
return socketMessage(jsonrpc) | ||
return socketMessageAction(jsonrpc) | ||
} | ||
@@ -591,3 +591,2 @@ sessionChannel.close() | ||
const sessionChannel = eventChannel(() => () => {}) | ||
const dispatchedActions: unknown[] = [] | ||
@@ -604,3 +603,3 @@ return expectSaga(sessionChannelWatcher, { | ||
runSaga = false | ||
return socketMessage(jsonrpc) | ||
return socketMessageAction(jsonrpc) | ||
} | ||
@@ -607,0 +606,0 @@ sessionChannel.close() |
import { SagaIterator, Channel, eventChannel, EventChannel } from 'redux-saga' | ||
import { call, put, take, fork } from 'redux-saga/effects' | ||
import { call, put, take, fork, select } from 'redux-saga/effects' | ||
import { PayloadAction } from '@reduxjs/toolkit' | ||
@@ -12,3 +12,3 @@ import { BaseSession } from '../../../BaseSession' | ||
import { ExecuteActionParams, WebRTCCall } from '../../interfaces' | ||
import { executeAction, socketMessage } from '../../actions' | ||
import { executeAction, socketMessageAction } from '../../actions' | ||
import { componentActions } from '../' | ||
@@ -18,2 +18,4 @@ import { BladeMethod, VertoMethod } from '../../../utils/constants' | ||
import { logger } from '../../../utils' | ||
import { getAuthStatus } from '../session/sessionSelectors' | ||
import { SessionAuthStatus } from '../../../utils/interfaces' | ||
@@ -74,3 +76,7 @@ type SessionSagaParams = { | ||
const action = yield take(executeAction.type) | ||
yield fork(worker, action) | ||
const authStatus: SessionAuthStatus = yield select(getAuthStatus) | ||
if (authStatus === 'authorized') { | ||
yield fork(worker, action) | ||
} | ||
} | ||
@@ -276,3 +282,3 @@ } | ||
logger.debug('Inbound WebSocket Message', action) | ||
if (action.type !== socketMessage.type) { | ||
if (action.type !== socketMessageAction.type) { | ||
yield put(action) | ||
@@ -279,0 +285,0 @@ return |
@@ -21,2 +21,3 @@ import { Store } from 'redux' | ||
authError: undefined, | ||
authCount: 1, | ||
}) | ||
@@ -23,0 +24,0 @@ }) |
@@ -1,2 +0,2 @@ | ||
import { createSlice, PayloadAction } from '@reduxjs/toolkit' | ||
import { PayloadAction } from '@reduxjs/toolkit' | ||
import { SessionState } from '../../interfaces' | ||
@@ -6,4 +6,6 @@ import { | ||
SessionAuthError, | ||
SessionAuthStatus, | ||
} from '../../../utils/interfaces' | ||
import { destroyAction, authError } from '../../actions' | ||
import { createDestroyableSlice } from '../../utils/createDestroyableSlice' | ||
import { authErrorAction } from '../../actions' | ||
@@ -15,5 +17,6 @@ export const initialSessionState: Readonly<SessionState> = { | ||
authError: undefined, | ||
authCount: 0, | ||
} | ||
const sessionSlice = createSlice({ | ||
const sessionSlice = createDestroyableSlice({ | ||
name: 'session', | ||
@@ -24,12 +27,13 @@ initialState: initialSessionState, | ||
state.authStatus = 'authorized' | ||
state.authCount += 1 | ||
state.protocol = payload?.result?.protocol ?? '' | ||
state.iceServers = payload?.result?.iceServers ?? [] | ||
}, | ||
authStatus: (state, { payload }: PayloadAction<SessionAuthStatus>) => { | ||
state.authStatus = payload | ||
}, | ||
}, | ||
extraReducers: (builder) => { | ||
builder.addCase(destroyAction.type, () => { | ||
return initialSessionState | ||
}) | ||
builder.addCase( | ||
authError.type, | ||
authErrorAction.type, | ||
(state, { payload }: PayloadAction<{ error: SessionAuthError }>) => { | ||
@@ -36,0 +40,0 @@ state.authStatus = 'unauthorized' |
@@ -16,2 +16,4 @@ import { configureStore as rtConfigureStore } from '@reduxjs/toolkit' | ||
export type SDKStore = ReturnType<typeof configureStore> | ||
const configureStore = (options: ConfigureStoreOptions) => { | ||
@@ -46,3 +48,6 @@ const { | ||
return store | ||
return { | ||
...store, | ||
runSaga: sagaMiddleware.run, | ||
} | ||
} | ||
@@ -49,0 +54,0 @@ |
import { PayloadAction } from '@reduxjs/toolkit' | ||
import type { Saga, Task, SagaIterator } from '@redux-saga/types' | ||
import { | ||
@@ -48,2 +49,3 @@ JSONRPCResponse, | ||
authError?: SessionAuthError | ||
authCount: number | ||
} | ||
@@ -54,2 +56,3 @@ | ||
session: SessionState | ||
executeQueue: ExecuteQueueState | ||
} | ||
@@ -63,1 +66,12 @@ | ||
} | ||
export interface ExecuteQueueState { | ||
queue: ExecuteActionParams[] | ||
} | ||
export interface CustomSagaParams<T> { | ||
instance: T | ||
runSaga: <S extends Saga>(saga: S, ...args: Parameters<S>) => Task | ||
} | ||
export type CustomSaga<T> = (params: CustomSagaParams<T>) => SagaIterator<any> |
import { combineReducers } from '@reduxjs/toolkit' | ||
import { componentReducer, sessionReducer } from './features' | ||
import { | ||
componentReducer, | ||
sessionReducer, | ||
executeQueueReducer, | ||
} from './features' | ||
@@ -7,2 +11,3 @@ export const rootReducer = combineReducers({ | ||
session: sessionReducer, | ||
executeQueue: executeQueueReducer, | ||
}) |
@@ -14,13 +14,18 @@ import { channel, eventChannel } from 'redux-saga' | ||
} from './features/session/sessionSaga' | ||
import { | ||
executeQueueWatcher, | ||
flushExecuteQueueWorker, | ||
} from './features/executeQueue/executeQueueSaga' | ||
import { pubSubSaga } from './features/pubSub/pubSubSaga' | ||
import { sessionActions } from './features' | ||
import { | ||
sessionConnected, | ||
sessionDisconnected, | ||
authSuccess, | ||
authError, | ||
socketError, | ||
socketClosed, | ||
sessionConnectedAction, | ||
sessionDisconnectedAction, | ||
authSuccessAction, | ||
authErrorAction, | ||
socketErrorAction, | ||
socketClosedAction, | ||
destroyAction, | ||
initAction, | ||
closeConnectionAction, | ||
} from './actions' | ||
@@ -63,3 +68,3 @@ import { AuthError } from '../CustomErrors' | ||
}) | ||
.put(pubSubChannel, sessionDisconnected()) | ||
.put(pubSubChannel, sessionDisconnectedAction()) | ||
.run() | ||
@@ -71,6 +76,6 @@ }) | ||
const actions = [ | ||
authSuccess.type, | ||
authError.type, | ||
socketError.type, | ||
socketClosed.type, | ||
authSuccessAction.type, | ||
authErrorAction.type, | ||
socketErrorAction.type, | ||
socketClosedAction.type, | ||
] | ||
@@ -96,3 +101,3 @@ const session = { | ||
saga.next().take(actions) | ||
saga.next(authSuccess()).fork(startSaga, options) | ||
saga.next(authSuccessAction()).fork(startSaga, options) | ||
// Saga waits again for actions due to the while loop | ||
@@ -106,3 +111,5 @@ saga.next().take(actions) | ||
try { | ||
saga.next(authError({ error: { code: 123, error: 'Protocol Error' } })) | ||
saga.next( | ||
authErrorAction({ error: { code: 123, error: 'Protocol Error' } }) | ||
) | ||
} catch (error) { | ||
@@ -120,3 +127,3 @@ expect(error).toBeInstanceOf(AuthError) | ||
saga.next().take(actions) | ||
saga.next(socketClosed()).fork(socketClosedWorker, options) | ||
saga.next(socketClosedAction()).fork(socketClosedWorker, options) | ||
// Saga waits again for actions due to the while loop | ||
@@ -134,4 +141,2 @@ saga.next().take(actions) | ||
}) | ||
const pubSubChannel = channel() | ||
const sessionChannel = eventChannel(() => () => {}) | ||
const userOptions = { | ||
@@ -146,2 +151,6 @@ token: '', | ||
it('should create the session, the sessionChannel and fork watchers', () => { | ||
const pubSubChannel = channel() | ||
pubSubChannel.close = jest.fn() | ||
const sessionChannel = eventChannel(() => () => {}) | ||
sessionChannel.close = jest.fn() | ||
const saga = testSaga(initSessionSaga, SessionConstructor, userOptions) | ||
@@ -161,3 +170,7 @@ saga.next(sessionChannel).call(createSessionChannel, session) | ||
}) | ||
saga.next().take(destroyAction.type) | ||
saga.next().isDone() | ||
expect(pubSubChannel.close).toHaveBeenCalledTimes(1) | ||
expect(sessionChannel.close).toHaveBeenCalledTimes(1) | ||
saga.next().isDone() | ||
expect(session.connect).toHaveBeenCalledTimes(1) | ||
@@ -190,2 +203,3 @@ }) | ||
const executeActionTask = { cancel: jest.fn() } | ||
const executeQueueCallTask = { cancel: jest.fn() } | ||
@@ -202,5 +216,7 @@ const saga = testSaga(startSaga, options) | ||
.put(sessionActions.connected(session.bladeConnectResult)) | ||
saga.next().put(pubSubChannel, sessionConnected()) | ||
saga.next().put(pubSubChannel, sessionConnectedAction()) | ||
saga.next().take(destroyAction.type) | ||
saga.next().fork(flushExecuteQueueWorker) | ||
saga.next(executeQueueCallTask).take(closeConnectionAction.type) | ||
saga.next().isDone() | ||
@@ -210,4 +226,3 @@ | ||
expect(executeActionTask.cancel).toHaveBeenCalledTimes(1) | ||
expect(pubSubChannel.close).toHaveBeenCalledTimes(1) | ||
expect(sessionChannel.close).toHaveBeenCalledTimes(1) | ||
expect(executeQueueCallTask.cancel).toHaveBeenCalledTimes(1) | ||
}) | ||
@@ -232,2 +247,3 @@ }) | ||
saga.next().fork(executeQueueWatcher) | ||
saga.next().take(initAction.type) | ||
@@ -234,0 +250,0 @@ saga.next().call(initSessionSaga, SessionConstructor, userOptions) |
@@ -12,11 +12,21 @@ import { Task, SagaIterator, Channel } from '@redux-saga/types' | ||
import { | ||
flushExecuteQueueWorker, | ||
executeQueueWatcher, | ||
} from './features/executeQueue/executeQueueSaga' | ||
import { | ||
initAction, | ||
destroyAction, | ||
sessionReconnecting, | ||
sessionDisconnected, | ||
sessionConnected, | ||
closeConnectionAction, | ||
sessionReconnectingAction, | ||
sessionDisconnectedAction, | ||
sessionConnectedAction, | ||
} from './actions' | ||
import { sessionActions } from './features' | ||
import { BaseSession } from '..' | ||
import { authError, authSuccess, socketClosed, socketError } from './actions' | ||
import { | ||
authErrorAction, | ||
authSuccessAction, | ||
socketClosedAction, | ||
socketErrorAction, | ||
} from './actions' | ||
import { AuthError } from '../CustomErrors' | ||
@@ -65,2 +75,6 @@ | ||
session.connect() | ||
yield take(destroyAction.type) | ||
pubSubChannel.close() | ||
sessionChannel.close() | ||
} | ||
@@ -78,3 +92,3 @@ | ||
if (session.status === 'reconnecting') { | ||
yield put(pubSubChannel, sessionReconnecting()) | ||
yield put(pubSubChannel, sessionReconnectingAction()) | ||
yield delay(Math.random() * 2000) | ||
@@ -84,3 +98,3 @@ yield call(session.connect) | ||
sessionChannel.close() | ||
yield put(pubSubChannel, sessionDisconnected()) | ||
yield put(pubSubChannel, sessionDisconnectedAction()) | ||
} | ||
@@ -92,13 +106,13 @@ } | ||
const action = yield take([ | ||
authSuccess.type, | ||
authError.type, | ||
socketError.type, | ||
socketClosed.type, | ||
authSuccessAction.type, | ||
authErrorAction.type, | ||
socketErrorAction.type, | ||
socketClosedAction.type, | ||
]) | ||
switch (action.type) { | ||
case authSuccess.type: | ||
case authSuccessAction.type: | ||
yield fork(startSaga, options) | ||
break | ||
case authError.type: { | ||
case authErrorAction.type: { | ||
const { error: authError } = action.payload | ||
@@ -110,3 +124,3 @@ const error = authError | ||
} | ||
case socketError.type: | ||
case socketErrorAction.type: | ||
// TODO: define if we want to emit external events here. | ||
@@ -118,3 +132,3 @@ // yield put(pubSubChannel, { | ||
break | ||
case socketClosed.type: | ||
case socketClosedAction.type: | ||
yield fork(socketClosedWorker, options) | ||
@@ -126,3 +140,3 @@ } | ||
export function* startSaga(options: StartSagaOptions): SagaIterator { | ||
const { session, sessionChannel, pubSubChannel, userOptions } = options | ||
const { session, pubSubChannel, userOptions } = options | ||
@@ -139,13 +153,20 @@ const pubSubTask: Task = yield fork(pubSubSaga, { | ||
yield put(sessionActions.connected(session.bladeConnectResult)) | ||
yield put(pubSubChannel, sessionConnected()) | ||
yield put(pubSubChannel, sessionConnectedAction()) | ||
/** | ||
* Wait for a destroyAction to teardown all the things | ||
* Will take care of executing any pending blade.execute we have in | ||
* the queue | ||
*/ | ||
yield take(destroyAction.type) | ||
const flushExecuteQueueTask: Task = yield fork(flushExecuteQueueWorker) | ||
/** | ||
* When `closeConnectionAction` is dispatched we'll teardown all the | ||
* tasks created by this saga since `startSaga` is meant to be | ||
* re-executed every time the user reconnects. | ||
*/ | ||
yield take(closeConnectionAction.type) | ||
pubSubTask.cancel() | ||
executeActionTask.cancel() | ||
pubSubChannel.close() | ||
sessionChannel.close() | ||
flushExecuteQueueTask.cancel() | ||
} | ||
@@ -159,2 +180,4 @@ | ||
return function* root(userOptions: UserOptions): SagaIterator { | ||
yield fork(executeQueueWatcher) | ||
/** | ||
@@ -161,0 +184,0 @@ * Wait for an initAction to start |
@@ -26,2 +26,8 @@ import { configureStore } from './redux' | ||
export const wait = (ms: number) => { | ||
return new Promise((resolve) => { | ||
setTimeout(resolve, ms) | ||
}) | ||
} | ||
export const bladeConnectResultVRT: IBladeConnectResult = { | ||
@@ -28,0 +34,0 @@ session_restored: false, |
@@ -14,2 +14,4 @@ export const STORAGE_PREFIX = '@signalwire:' | ||
export const GLOBAL_VIDEO_EVENTS = ['room.started', 'room.ended'] as const | ||
export enum BladeMethod { | ||
@@ -16,0 +18,0 @@ Broadcast = 'blade.broadcast', |
@@ -47,2 +47,16 @@ import EventEmitter from 'eventemitter3' | ||
export { assertEventEmitter, EventEmitter, getEventEmitter } | ||
const getNamespacedEvent = ({ | ||
namespace, | ||
event, | ||
}: { | ||
namespace: string | ||
event: string | ||
}) => { | ||
if (!namespace) { | ||
return event | ||
} | ||
return `${namespace}:${event}` | ||
} | ||
export { assertEventEmitter, EventEmitter, getEventEmitter, getNamespacedEvent } |
@@ -1,2 +0,3 @@ | ||
import { STORAGE_PREFIX } from './constants' | ||
import { STORAGE_PREFIX, GLOBAL_VIDEO_EVENTS } from './constants' | ||
import { RoomEventNames } from './interfaces' | ||
@@ -49,1 +50,18 @@ export { v4 as uuid } from 'uuid' | ||
} | ||
export const isGlobalEvent = (event: RoomEventNames) => { | ||
// @ts-ignore | ||
return GLOBAL_VIDEO_EVENTS.includes(event) | ||
} | ||
export const getGlobalEvents = (kind: 'all' | 'video' = 'all') => { | ||
switch (kind) { | ||
case 'video': | ||
return GLOBAL_VIDEO_EVENTS | ||
default: | ||
// prettier-ignore | ||
return [ | ||
...GLOBAL_VIDEO_EVENTS, | ||
] | ||
} | ||
} |
@@ -1,4 +0,5 @@ | ||
import { Store } from 'redux' | ||
import type { EventEmitter } from '../utils/EventEmitter' | ||
import { BaseSession } from '../BaseSession' | ||
import { SDKStore } from '../redux' | ||
import { GLOBAL_VIDEO_EVENTS } from './constants' | ||
@@ -10,3 +11,3 @@ /** | ||
EventEmitter, | ||
'on' | 'off' | 'once' | 'emit' | 'removeAllListeners' | ||
'on' | 'off' | 'once' | 'emit' | 'removeAllListeners' | 'eventNames' | ||
> | ||
@@ -58,3 +59,3 @@ | ||
export interface BaseClientOptions extends UserOptions { | ||
store: Store | ||
store: SDKStore | ||
emitter: Emitter | ||
@@ -64,3 +65,3 @@ } | ||
export interface BaseComponentOptions { | ||
store: Store | ||
store: SDKStore | ||
emitter: Emitter | ||
@@ -216,10 +217,9 @@ } | ||
type RoomMemberType = 'member' | 'screen' | ||
type RoomMemberType = 'member' | 'screen' | 'device' | ||
interface RoomMemberCommon { | ||
id: string | ||
room_session_id: string | ||
room_id: string | ||
} | ||
interface RoomMemberProperties { | ||
scope_id: string | ||
parent_id?: string | ||
input_volume: number | ||
@@ -230,3 +230,2 @@ input_sensitivity: number | ||
deaf: boolean | ||
// FIXME: review this for different types | ||
type: RoomMemberType | ||
@@ -351,2 +350,7 @@ visible: boolean | ||
/** | ||
* List of all room members | ||
*/ | ||
type RoomMembersMethod = 'members.get' | ||
/** | ||
* List of all room member methods | ||
@@ -380,2 +384,3 @@ */ | ||
| 'video.show_video_muted' | ||
| `video.${RoomMembersMethod}` | ||
| `video.${RoomMemberMethod}` | ||
@@ -407,1 +412,7 @@ | `video.${RoomLayoutMethod}` | ||
} | ||
export type GlobalVideoEvents = typeof GLOBAL_VIDEO_EVENTS[number] | ||
export type RoomCustomMethods<T> = { | ||
[k in keyof T]: PropertyDescriptor | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1975047
182
21410