@100mslive/react-sdk 0.0.16 → 0.0.18-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/hooks/useAVToggle.js +1 -0
  2. package/dist/hooks/useAVToggle.js.map +1 -0
  3. package/dist/hooks/useAudioLevelStyles.js +1 -0
  4. package/dist/hooks/useAudioLevelStyles.js.map +1 -0
  5. package/dist/hooks/useAutoplayError.js +1 -0
  6. package/dist/hooks/useAutoplayError.js.map +1 -0
  7. package/dist/hooks/useCustomEvent.js +1 -0
  8. package/dist/hooks/useCustomEvent.js.map +1 -0
  9. package/dist/hooks/useDevices.js +1 -0
  10. package/dist/hooks/useDevices.js.map +1 -0
  11. package/dist/hooks/useParticipantList.js +1 -0
  12. package/dist/hooks/useParticipantList.js.map +1 -0
  13. package/dist/hooks/usePreviewJoin.js +1 -0
  14. package/dist/hooks/usePreviewJoin.js.map +1 -0
  15. package/dist/hooks/useRecordingStreaming.js +1 -0
  16. package/dist/hooks/useRecordingStreaming.js.map +1 -0
  17. package/dist/hooks/useRemoteAVToggle.js +1 -0
  18. package/dist/hooks/useRemoteAVToggle.js.map +1 -0
  19. package/dist/hooks/useScreenShare.js +1 -0
  20. package/dist/hooks/useScreenShare.js.map +1 -0
  21. package/dist/hooks/useVideo.js +1 -0
  22. package/dist/hooks/useVideo.js.map +1 -0
  23. package/dist/hooks/useVideoList.js +1 -0
  24. package/dist/hooks/useVideoList.js.map +1 -0
  25. package/dist/index.cjs.js +1 -0
  26. package/dist/index.cjs.js.map +1 -0
  27. package/dist/index.js +1 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/node_modules/tslib/tslib.es6.js +1 -0
  30. package/dist/node_modules/tslib/tslib.es6.js.map +1 -0
  31. package/dist/node_modules/zustand/esm/shallow.js +1 -0
  32. package/dist/node_modules/zustand/esm/shallow.js.map +1 -0
  33. package/dist/primitives/HmsRoomProvider.js +1 -0
  34. package/dist/primitives/HmsRoomProvider.js.map +1 -0
  35. package/dist/primitives/store.js +1 -0
  36. package/dist/primitives/store.js.map +1 -0
  37. package/dist/utils/commons.js +1 -0
  38. package/dist/utils/commons.js.map +1 -0
  39. package/dist/utils/groupBy.js +1 -0
  40. package/dist/utils/groupBy.js.map +1 -0
  41. package/dist/utils/isBrowser.js +1 -0
  42. package/dist/utils/isBrowser.js.map +1 -0
  43. package/dist/utils/layout.js +1 -0
  44. package/dist/utils/layout.js.map +1 -0
  45. package/dist/utils/logger.js +1 -0
  46. package/dist/utils/logger.js.map +1 -0
  47. package/package.json +6 -5
  48. package/src/hooks/types.ts +6 -0
  49. package/src/hooks/useAVToggle.ts +62 -0
  50. package/src/hooks/useAudioLevelStyles.ts +37 -0
  51. package/src/hooks/useAutoplayError.ts +41 -0
  52. package/src/hooks/useCustomEvent.ts +85 -0
  53. package/src/hooks/useDevices.ts +93 -0
  54. package/src/hooks/useParticipantList.ts +27 -0
  55. package/src/hooks/usePreviewJoin.ts +132 -0
  56. package/src/hooks/useRecordingStreaming.ts +34 -0
  57. package/src/hooks/useRemoteAVToggle.ts +101 -0
  58. package/src/hooks/useScreenShare.ts +76 -0
  59. package/src/hooks/useVideo.ts +77 -0
  60. package/src/hooks/useVideoList.ts +162 -0
  61. package/src/index.ts +40 -0
  62. package/src/primitives/HmsRoomProvider.ts +203 -0
  63. package/src/primitives/store.ts +59 -0
  64. package/src/primitives/types.ts +6 -0
  65. package/src/utils/commons.ts +14 -0
  66. package/src/utils/groupBy.ts +29 -0
  67. package/src/utils/isBrowser.ts +1 -0
  68. package/src/utils/layout.ts +466 -0
  69. package/src/utils/logger.ts +62 -0
@@ -0,0 +1,162 @@
1
+ import { HMSPeer, HMSTrack, HMSTrackID, selectTracksMap } from '@100mslive/hms-video-store';
2
+ import React, { useMemo } from 'react';
3
+ import {
4
+ calculateLayoutSizes,
5
+ chunkElements,
6
+ getModeAspectRatio,
7
+ getVideoTracksFromPeers,
8
+ TrackWithPeer,
9
+ } from '../utils/layout';
10
+ import { useHMSVanillaStore } from '../primitives/HmsRoomProvider';
11
+ import { useResizeDetector } from 'react-resize-detector';
12
+
13
+ export interface useVideoListInput {
14
+ /**
15
+ * peers is the list of all peers you need to display
16
+ */
17
+ peers: HMSPeer[];
18
+ /**
19
+ * Max tiles in a page. Overrides maxRowCount and maxColCount
20
+ */
21
+ maxTileCount?: number;
22
+ /**
23
+ * Max rows in a page. Only applied if maxTileCount is not present
24
+ */
25
+ maxRowCount?: number;
26
+ /**
27
+ * Max columns in a page. Only applied if maxTileCount and maxRowCount are not present
28
+ */
29
+ maxColCount?: number;
30
+ /**
31
+ * A function which tells whether to show the screenShare for a peer who is screensharing. A peer is passed
32
+ * and a boolean value is expected.
33
+ * This can be useful if there are multiple screenShares in the room where you may want to show the main one in the
34
+ * center view and others in video list along side other tiles. No screenShare is included by default.
35
+ * e.g. includeScreenShare = (peer) => return peer.id !== mainScreenSharingPeer.id
36
+ */
37
+ includeScreenShareForPeer?: (peer: HMSPeer) => boolean;
38
+ /**
39
+ * Aspect ratio of VideoTiles, ideally this should be the same as the aspect ratio selected for
40
+ * capture in the dashboard template.
41
+ */
42
+ aspectRatio?: { width: number; height: number };
43
+ /**
44
+ * By default this will be true. Only publishing(audio/video/screen) peers in the passed in peer list
45
+ * will be filtered. If you wish to show all peers, pass false for this.
46
+ */
47
+ filterNonPublishingPeers?: boolean;
48
+ /**
49
+ * Height that would be subtracted from the parent's height to give the available height, use case: if your pagination is inside the parent component then offsetY would be the height of pagination
50
+ */
51
+ offsetY?: number;
52
+ }
53
+
54
+ export interface useVideoListTile extends TrackWithPeer {
55
+ width: number;
56
+ height: number;
57
+ }
58
+
59
+ export interface useVideoResult {
60
+ /**
61
+ * This returns a list of all pages with every page containing the list of all tiles on it.
62
+ */
63
+ pagesWithTiles: useVideoListTile[][];
64
+ /**
65
+ * add the ref to the element going to render the video list, this is used to measure the available
66
+ * space/dimensions in order to calculate the best fit
67
+ */
68
+ ref: React.MutableRefObject<any>;
69
+ }
70
+
71
+ const DEFAULTS = {
72
+ aspectRatio: {
73
+ width: 1,
74
+ height: 1,
75
+ },
76
+ };
77
+
78
+ /**
79
+ * This hook can be used to build a paginated gallery view of video tiles. You can give the hook
80
+ * a list of all the peers which need to be shown and it tells you how to structure the UI by giving
81
+ * a list of pages with every page having a list of video tiles.
82
+ * Please check the documentation of input and output types for more details.
83
+ */
84
+ export const useVideoList = ({
85
+ peers,
86
+ maxTileCount,
87
+ maxColCount,
88
+ maxRowCount,
89
+ includeScreenShareForPeer = () => false,
90
+ aspectRatio = DEFAULTS.aspectRatio,
91
+ filterNonPublishingPeers = true,
92
+ offsetY = 0,
93
+ }: useVideoListInput): useVideoResult => {
94
+ const { width = 0, height = 0, ref } = useResizeDetector();
95
+ const store = useHMSVanillaStore();
96
+ // using vanilla store as we don't need re-rendering everytime something in a track changes
97
+ const tracksMap: Record<HMSTrackID, HMSTrack> = store.getState(selectTracksMap);
98
+ const tracksWithPeer: TrackWithPeer[] = getVideoTracksFromPeers(
99
+ peers,
100
+ tracksMap,
101
+ includeScreenShareForPeer,
102
+ filterNonPublishingPeers,
103
+ );
104
+ const finalAspectRatio = useMemo(() => {
105
+ if (aspectRatio) {
106
+ return aspectRatio;
107
+ }
108
+ const modeAspectRatio = getModeAspectRatio(tracksWithPeer);
109
+ // Default to 1 if there are no video tracks
110
+ return {
111
+ width: modeAspectRatio || 1,
112
+ height: 1,
113
+ };
114
+ }, [aspectRatio, tracksWithPeer]);
115
+ const count = tracksWithPeer.length;
116
+ const {
117
+ tilesInFirstPage,
118
+ defaultWidth,
119
+ defaultHeight,
120
+ lastPageWidth,
121
+ lastPageHeight,
122
+ isLastPageDifferentFromFirstPage,
123
+ } = useMemo(
124
+ () =>
125
+ calculateLayoutSizes({
126
+ count,
127
+ parentWidth: Math.floor(width),
128
+ parentHeight: Math.floor(height) - Math.min(height, offsetY),
129
+ maxTileCount,
130
+ maxRowCount,
131
+ maxColCount,
132
+ aspectRatio: finalAspectRatio,
133
+ }),
134
+ [count, width, height, maxTileCount, maxRowCount, maxColCount, finalAspectRatio, offsetY],
135
+ );
136
+ const chunkedTracksWithPeer = useMemo(
137
+ () =>
138
+ chunkElements<TrackWithPeer>({
139
+ elements: tracksWithPeer,
140
+ tilesInFirstPage,
141
+ onlyOnePage: false,
142
+ isLastPageDifferentFromFirstPage,
143
+ defaultWidth,
144
+ defaultHeight,
145
+ lastPageWidth,
146
+ lastPageHeight,
147
+ }),
148
+ [
149
+ tracksWithPeer,
150
+ tilesInFirstPage,
151
+ isLastPageDifferentFromFirstPage,
152
+ defaultWidth,
153
+ defaultHeight,
154
+ lastPageWidth,
155
+ lastPageHeight,
156
+ ],
157
+ );
158
+ return {
159
+ pagesWithTiles: chunkedTracksWithPeer,
160
+ ref,
161
+ };
162
+ };
package/src/index.ts ADDED
@@ -0,0 +1,40 @@
1
+ export {
2
+ HMSRoomProvider,
3
+ useHMSStore,
4
+ useHMSActions,
5
+ useHMSNotifications,
6
+ useHMSVanillaStore,
7
+ useHMSVanillaNotifications,
8
+ useHMSStatsStore,
9
+ } from './primitives/HmsRoomProvider';
10
+ export { usePreviewJoin } from './hooks/usePreviewJoin';
11
+ export { useAVToggle } from './hooks/useAVToggle';
12
+ export { useVideo } from './hooks/useVideo';
13
+ export { useScreenShare } from './hooks/useScreenShare';
14
+ export { useRemoteAVToggle } from './hooks/useRemoteAVToggle';
15
+ export { useVideoList } from './hooks/useVideoList';
16
+ export { useAudioLevelStyles } from './hooks/useAudioLevelStyles';
17
+ export { useDevices, DeviceType } from './hooks/useDevices';
18
+ export { useParticipantList } from './hooks/useParticipantList';
19
+ export { useRecordingStreaming } from './hooks/useRecordingStreaming';
20
+ export { useAutoplayError } from './hooks/useAutoplayError';
21
+ export { useCustomEvent } from './hooks/useCustomEvent';
22
+ // types
23
+ export type { hooksErrHandler } from './hooks/types';
24
+ export type { usePreviewInput, usePreviewResult } from './hooks/usePreviewJoin';
25
+ export type { useVideoListInput, useVideoResult, useVideoListTile } from './hooks/useVideoList';
26
+ export type { useAVToggleResult } from './hooks/useAVToggle';
27
+ export type { useDevicesResult } from './hooks/useDevices';
28
+ export type { useScreenShareResult } from './hooks/useScreenShare';
29
+ export type { useRemoteAVToggleResult } from './hooks/useRemoteAVToggle';
30
+ export type { useRecordingStreamingResult } from './hooks/useRecordingStreaming';
31
+ export type { useParticipantListResult } from './hooks/useParticipantList';
32
+ export type { useVideoInput, useVideoOutput } from './hooks/useVideo';
33
+ export type { useAutoplayErrorResult } from './hooks/useAutoplayError';
34
+ export type { useCustomEventInput, useCustomEventResult } from './hooks/useCustomEvent';
35
+
36
+ // helpers
37
+ export { throwErrorHandler } from './utils/commons';
38
+
39
+ // reexport everything from store so app can import everything directly from this
40
+ export * from '@100mslive/hms-video-store';
@@ -0,0 +1,203 @@
1
+ import React, { createContext, PropsWithChildren, useContext, useEffect, useState } from 'react';
2
+ import {
3
+ HMSReactiveStore,
4
+ HMSStore,
5
+ HMSActions,
6
+ HMSNotification,
7
+ HMSNotifications,
8
+ HMSStatsStore,
9
+ HMSStats,
10
+ HMSStoreWrapper,
11
+ HMSNotificationTypes,
12
+ } from '@100mslive/hms-video-store';
13
+ import create from 'zustand';
14
+ import { HMSContextProviderProps, makeHMSStoreHook, hooksErrorMessage, makeHMSStatsStoreHook } from './store';
15
+ import { isBrowser } from '../utils/isBrowser';
16
+
17
+ export interface HMSRoomProviderProps {
18
+ actions?: HMSActions;
19
+ store?: HMSStoreWrapper;
20
+ notifications?: HMSNotifications;
21
+ stats?: HMSStats;
22
+ /**
23
+ * if true this will enable webrtc stats collection
24
+ */
25
+ isHMSStatsOn?: boolean;
26
+ }
27
+
28
+ /**
29
+ * only one context is being created currently. This would need to be changed if multiple
30
+ * rooms have to be supported, where every room will have its own context, provider, store and actions.
31
+ */
32
+ const HMSContext = createContext<HMSContextProviderProps | null>(null);
33
+
34
+ let providerProps: HMSContextProviderProps;
35
+ /**
36
+ * top level wrapper for using react sdk hooks. This doesn't have any mandatory arguments, if you are already
37
+ * initialising the sdk on your side, you can pass in the primitives from there as well to use hooks for
38
+ * react part of your code.
39
+ * @constructor
40
+ */
41
+ // eslint-disable-next-line complexity
42
+ export const HMSRoomProvider: React.FC<PropsWithChildren<HMSRoomProviderProps>> = ({
43
+ children,
44
+ actions,
45
+ store,
46
+ notifications,
47
+ stats,
48
+ isHMSStatsOn = false,
49
+ }) => {
50
+ if (!providerProps) {
51
+ // adding a dummy function for setstate and destroy because zustan'd create expects them
52
+ // to be present but we don't expose them from the store.
53
+ const errFn = () => {
54
+ throw new Error('modifying store is not allowed');
55
+ };
56
+ if (actions && store) {
57
+ providerProps = {
58
+ actions: actions,
59
+ store: create<HMSStore>({
60
+ ...store,
61
+ setState: errFn,
62
+ destroy: errFn,
63
+ }),
64
+ };
65
+ if (notifications) {
66
+ providerProps.notifications = notifications;
67
+ }
68
+ if (stats) {
69
+ providerProps.statsStore = create<HMSStatsStore>({
70
+ getState: stats.getState,
71
+ subscribe: stats.subscribe,
72
+ setState: errFn,
73
+ destroy: errFn,
74
+ });
75
+ }
76
+ } else {
77
+ const hmsReactiveStore = new HMSReactiveStore();
78
+ providerProps = {
79
+ actions: hmsReactiveStore.getActions(),
80
+ store: create<HMSStore>({
81
+ ...hmsReactiveStore.getStore(),
82
+ setState: errFn,
83
+ destroy: errFn,
84
+ }), // convert vanilla store in react hook
85
+ notifications: hmsReactiveStore.getNotifications(),
86
+ };
87
+
88
+ if (isHMSStatsOn) {
89
+ const stats = hmsReactiveStore.getStats();
90
+ providerProps.statsStore = create<HMSStatsStore>({
91
+ getState: stats.getState,
92
+ subscribe: stats.subscribe,
93
+ setState: errFn,
94
+ destroy: errFn,
95
+ });
96
+ }
97
+ }
98
+ }
99
+
100
+ useEffect(() => {
101
+ if (isBrowser) {
102
+ window.addEventListener('beforeunload', () => providerProps.actions.leave());
103
+ window.addEventListener('onunload', () => providerProps.actions.leave());
104
+ }
105
+ }, []);
106
+
107
+ return React.createElement(HMSContext.Provider, { value: providerProps }, children);
108
+ };
109
+
110
+ /**
111
+ * `useHMSStore` is a read only hook which can be passed a selector to read data.
112
+ * The hook can only be used in a component if HMSRoomProvider is present in its ancestors.
113
+ */
114
+ export const useHMSStore = makeHMSStoreHook(HMSContext);
115
+
116
+ export const useHMSStatsStore = makeHMSStatsStoreHook(HMSContext);
117
+
118
+ /**
119
+ * `useHMSVanillaStore` is a read only hook which returns the vanilla HMSStore.
120
+ * Usage:
121
+ * ```
122
+ * const hmsStore = useHMSVanillaStore();
123
+ * const dominantSpeaker = hmsStore.getState(selectDominantSpeaker);
124
+ * ```
125
+ *
126
+ * Note: There's no need to use the vanilla hmsStore in React components.
127
+ * This is used in rare cases where the store needs to be accessed outside a React component.
128
+ * For almost every case, `useHMSStore` would get the job done.
129
+ */
130
+ export const useHMSVanillaStore = () => {
131
+ const HMSContextConsumer = useContext(HMSContext);
132
+ if (!HMSContextConsumer) {
133
+ throw new Error(hooksErrorMessage);
134
+ }
135
+
136
+ return HMSContextConsumer.store;
137
+ };
138
+
139
+ /*
140
+ * `useHMSVanillaNotifications` returns the vanilla HMSNotifications object. This makes it a bit easier to ensure
141
+ * a notification is processed only once in your components. The other way is to use the hook version and put
142
+ * the component high enough in the chain.
143
+ * Usage:
144
+ * ```
145
+ * useEffect(() => {
146
+ * const unsub = notifications.onNotification((notification) => {
147
+ * console.log(notification);
148
+ * }, notificationType);
149
+ * return unsub;
150
+ * }, [])
151
+ * ```
152
+ */
153
+ export const useHMSVanillaNotifications = () => {
154
+ const HMSContextConsumer = useContext(HMSContext);
155
+ if (!HMSContextConsumer) {
156
+ throw new Error(hooksErrorMessage);
157
+ }
158
+ return HMSContextConsumer.notifications;
159
+ };
160
+
161
+ /*
162
+ * `useHMSActions` is a write only hook which can be used to dispatch actions.
163
+ */
164
+ export const useHMSActions = () => {
165
+ const HMSContextConsumer = useContext(HMSContext);
166
+ if (!HMSContextConsumer) {
167
+ throw new Error(hooksErrorMessage);
168
+ }
169
+ return HMSContextConsumer.actions;
170
+ };
171
+
172
+ /**
173
+ * `useHMSNotifications` is a read only hook which gives the latest notification(HMSNotification) received.
174
+ * @param type can be a string or an array of string for the types of notifications to listen to. If an array is passed
175
+ * either declare it outside the functional component or use a useMemo to make sure its reference stays same across
176
+ * rerenders for performance reasons.
177
+ */
178
+ export const useHMSNotifications = (type?: HMSNotificationTypes | HMSNotificationTypes[]) => {
179
+ const HMSContextConsumer = useContext(HMSContext);
180
+ const [notification, setNotification] = useState<HMSNotification | null>(null);
181
+
182
+ if (!HMSContextConsumer) {
183
+ throw new Error(hooksErrorMessage);
184
+ }
185
+
186
+ useEffect(() => {
187
+ if (!HMSContextConsumer.notifications) {
188
+ return;
189
+ }
190
+ const unsubscribe = HMSContextConsumer.notifications.onNotification(
191
+ (notification: HMSNotification) => setNotification(notification),
192
+ type,
193
+ );
194
+ return unsubscribe;
195
+ }, [HMSContextConsumer.notifications, type]);
196
+
197
+ return notification;
198
+ };
199
+
200
+ export const useIsHMSStatsOn = () => {
201
+ const HMSContextConsumer = useContext(HMSContext);
202
+ return Boolean(HMSContextConsumer?.statsStore);
203
+ };
@@ -0,0 +1,59 @@
1
+ import { EqualityChecker, StateSelector } from 'zustand';
2
+ import React, { useContext } from 'react';
3
+ import shallow from 'zustand/shallow';
4
+ import { HMSActions, HMSStore, HMSNotifications, HMSStatsStore, IStoreReadOnly } from '@100mslive/hms-video-store';
5
+ import HMSLogger from '../utils/logger';
6
+
7
+ export interface IHMSReactStore<S extends HMSStore | HMSStatsStore> extends IStoreReadOnly<S> {
8
+ <U>(selector: StateSelector<S, U>, equalityFn?: EqualityChecker<U>): U;
9
+ }
10
+
11
+ export const hooksErrorMessage =
12
+ 'It seems like you forgot to add your component within a top level HMSRoomProvider, please refer to 100ms react docs(https://docs.100ms.live/javascript/v2/features/integration#react-hooks) to check on the required steps for using this hook.';
13
+
14
+ export interface HMSContextProviderProps {
15
+ actions: HMSActions; // for actions which may also mutate store
16
+ store: IHMSReactStore<HMSStore>; // readonly store, don't mutate this
17
+ notifications?: HMSNotifications;
18
+ statsStore?: IHMSReactStore<HMSStatsStore>;
19
+ }
20
+
21
+ export function makeHMSStoreHook(hmsContext: React.Context<HMSContextProviderProps | null>) {
22
+ const useHMSStore = <StateSlice>(
23
+ selector: StateSelector<HMSStore, StateSlice>,
24
+ equalityFn: EqualityChecker<StateSlice> = shallow,
25
+ ) => {
26
+ if (!selector) {
27
+ HMSLogger.w(
28
+ 'fetching full store without passing any selector may have a heavy performance impact on your website.',
29
+ );
30
+ }
31
+ const HMSContextConsumer = useContext(hmsContext);
32
+ if (!HMSContextConsumer) {
33
+ throw new Error(hooksErrorMessage);
34
+ }
35
+ const useStore = HMSContextConsumer.store;
36
+ return useStore(selector, equalityFn);
37
+ };
38
+ return useHMSStore;
39
+ }
40
+
41
+ export function makeHMSStatsStoreHook(hmsContext: React.Context<HMSContextProviderProps | null>) {
42
+ const useHMSStatsStore = <StateSlice>(
43
+ selector: StateSelector<HMSStatsStore, StateSlice>,
44
+ equalityFn: EqualityChecker<StateSlice> = shallow,
45
+ ) => {
46
+ if (!selector) {
47
+ HMSLogger.w(
48
+ 'fetching full store without passing any selector may have a heavy performance impact on your website.',
49
+ );
50
+ }
51
+ const HMSContextConsumer = useContext(hmsContext);
52
+ if (!HMSContextConsumer) {
53
+ throw new Error(hooksErrorMessage);
54
+ }
55
+ const useStore = HMSContextConsumer.statsStore;
56
+ return useStore?.(selector, equalityFn);
57
+ };
58
+ return useHMSStatsStore;
59
+ }
@@ -0,0 +1,6 @@
1
+ import { EqualityChecker, StateSelector } from 'zustand';
2
+ import { HMSStore, IStoreReadOnly, HMSStatsStore } from '@100mslive/hms-video-store';
3
+
4
+ export interface IHMSReactStore<S extends HMSStore | HMSStatsStore> extends IStoreReadOnly<S> {
5
+ <U>(selector: StateSelector<S, U>, equalityFn?: EqualityChecker<U>): U;
6
+ }
@@ -0,0 +1,14 @@
1
+ import { hooksErrHandler } from '../hooks/types';
2
+ import HMSLogger from './logger';
3
+
4
+ const TAG = 'react-sdk';
5
+
6
+ export const logErrorHandler: hooksErrHandler = (err: Error, method?: string) => HMSLogger.e(TAG, method, err);
7
+
8
+ /**
9
+ * pass in this error handler to get the error thrown back to the UI for further handling, showing toast etc.
10
+ * @param err
11
+ */
12
+ export const throwErrorHandler: hooksErrHandler = (err: Error) => {
13
+ throw err;
14
+ };
@@ -0,0 +1,29 @@
1
+ import { HMSPeer } from '@100mslive/hms-video-store';
2
+ /**
3
+ * Give array like [
4
+ * { name: 'peer1', id: 1, roleName: 'role1' },
5
+ * { name: 'peer2', id: 2, roleName: 'role2' }
6
+ *]
7
+ * the output will be
8
+ * {
9
+ * 'role1': [{'name': 'peer1', id: 1, roleName: 'role1'}],
10
+ * 'role2': [{ name: 'peer2', id: 2, roleName: 'role2' }]
11
+ * }
12
+ * @param {HMSPeer[]} peers
13
+ * @returns
14
+ */
15
+ export const groupByRoles = (peers: HMSPeer[]) => {
16
+ if (!peers || !Array.isArray(peers) || peers.length === 0) {
17
+ return {};
18
+ }
19
+ return peers.reduce((res: Record<string, HMSPeer[]>, peer) => {
20
+ if (!peer.roleName) {
21
+ return res;
22
+ }
23
+ if (!res[peer.roleName]) {
24
+ res[peer.roleName] = [];
25
+ }
26
+ res[peer.roleName].push(peer);
27
+ return res;
28
+ }, {});
29
+ };
@@ -0,0 +1 @@
1
+ export const isBrowser = typeof window !== 'undefined';