Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@signalwire/core

Package Overview
Dependencies
Maintainers
1
Versions
199
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@signalwire/core - npm Package Compare versions

Comparing version 3.0.0-beta.1 to 3.0.0-beta.2

dist/core/src/redux/features/executeQueue/executeQueueSaga.d.ts

7

dist/core/src/BaseClient.d.ts

@@ -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 @@ *

69

dist/core/src/BaseComponent.d.ts

@@ -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

8

dist/core/src/index.d.ts

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc