@defcomm/meetingsdk 0.4.3 → 0.4.5

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.
package/dist/index.d.mts CHANGED
@@ -59,6 +59,34 @@ type ChatMessage = {
59
59
  } | null;
60
60
  target?: string | null;
61
61
  };
62
+ type PubSubMessage<T = unknown> = {
63
+ id: string;
64
+ topic: PubSubTopic;
65
+ sender_id: string;
66
+ sender_name?: string | null;
67
+ timestamp: number;
68
+ data: T;
69
+ };
70
+ type PubSubTopicConfig = {
71
+ SECURE_CHAT: {
72
+ publish: ChatInput;
73
+ message: ChatMessage;
74
+ };
75
+ REACTION: {
76
+ publish: {
77
+ emoji: string;
78
+ };
79
+ message: {
80
+ emoji: string;
81
+ };
82
+ };
83
+ };
84
+ type PubSubTopic = keyof PubSubTopicConfig;
85
+ type PubSubHandle<TPublish = unknown, TMessage = TPublish> = {
86
+ messages: PubSubMessage<TMessage>[];
87
+ publish: (data: TPublish) => void;
88
+ };
89
+ type PubSubHandleForTopic<T extends PubSubTopic> = PubSubHandle<PubSubTopicConfig[T]["publish"], PubSubTopicConfig[T]["message"]>;
62
90
  type Participant = {
63
91
  id: string;
64
92
  name?: string;
@@ -97,7 +125,6 @@ type MeetingConfig = {
97
125
  videoMuted?: boolean;
98
126
  token?: string;
99
127
  };
100
- type PubSubTopic = "SECURE_CHAT" | "REACTION";
101
128
  type RecordingInfo = {
102
129
  recording_id: string;
103
130
  started_at?: string;
@@ -241,6 +268,15 @@ declare class VideoSDKCore {
241
268
  }>;
242
269
  sendChatMessage(payload: ChatInput): void;
243
270
  sendReaction(reaction: string): void;
271
+ /**
272
+ * Generic PubSub publishing entry point.
273
+ *
274
+ * The public SDK exposes one PubSub API for all topics. The current SFU
275
+ * protocol still has dedicated wire messages for chat and reactions, so
276
+ * this method is the compatibility bridge. The application does not need
277
+ * to know about those wire-level message types.
278
+ */
279
+ publishPubSub<T extends PubSubTopic>(topic: T, data: PubSubTopicConfig[T]["publish"]): void;
244
280
  private cleanupRemoteParticipant;
245
281
  disconnect(): Promise<void>;
246
282
  private performDisconnect;
@@ -263,10 +299,6 @@ interface ParticipantInfo {
263
299
  [key: string]: any;
264
300
  }
265
301
 
266
- type PubSubHandle = {
267
- messages: ChatMessage[];
268
- publish: (input: ChatInput) => void;
269
- };
270
302
  type MeetingContextValue = {
271
303
  sdk: VideoSDKCore;
272
304
  join: (config?: Omit<MeetingConfig, "participantId">) => Promise<void>;
@@ -296,7 +328,8 @@ type MeetingContextValue = {
296
328
  presenterId: string | null;
297
329
  activeSpeakerIds: string[];
298
330
  recording: RecordingInfo | null;
299
- usePubSub: (topic: PubSubTopic) => PubSubHandle;
331
+ usePubSub: <T extends PubSubTopic>(topic: T) => PubSubHandleForTopic<T>;
332
+ onPubSubMessage: <T extends PubSubTopic>(topic: T, cb: (message: PubSubMessage<PubSubTopicConfig[T]["message"]>) => void) => () => void;
300
333
  approveJoinRequest: (requestId: string) => void;
301
334
  rejectJoinRequest: (requestId: string) => void;
302
335
  startRecording: () => Promise<void>;
@@ -358,10 +391,8 @@ declare const useMeeting: (handlers?: {
358
391
  presenterId: string | null;
359
392
  activeSpeakerIds: string[];
360
393
  recording: RecordingInfo | null;
361
- usePubSub: (topic: PubSubTopic) => {
362
- messages: ChatMessage[];
363
- publish: (input: ChatInput) => void;
364
- };
394
+ usePubSub: <T extends PubSubTopic>(topic: T) => PubSubHandleForTopic<T>;
395
+ onPubSubMessage: <T extends PubSubTopic>(topic: T, cb: (message: PubSubMessage<PubSubTopicConfig[T]["message"]>) => void) => () => void;
365
396
  approveJoinRequest: (requestId: string) => void;
366
397
  rejectJoinRequest: (requestId: string) => void;
367
398
  startRecording: () => Promise<void>;
@@ -456,4 +487,8 @@ declare class ActiveSpeakerDetector {
456
487
  destroy(): Promise<void>;
457
488
  }
458
489
 
459
- export { ActiveSpeakerDetector, type ChatInput, type MeetingConfig, MeetingProvider, MeetingState, type Participant, type ParticipantInfo, type Reaction, type RecordingInfo, type SFUConnectionState, type TrackInfo, VideoSDKCore, useLocalParticipant, useMeeting, useMeetingContext, useMeetingPreview, useParticipants, useRemoteMedia };
490
+ declare function usePubSub<T extends PubSubTopic>(topic: T, options?: {
491
+ onMessageReceived?: (message: PubSubMessage<PubSubTopicConfig[T]["message"]>) => void;
492
+ }): PubSubHandleForTopic<T>;
493
+
494
+ export { ActiveSpeakerDetector, type ChatInput, type MeetingConfig, MeetingProvider, MeetingState, type Participant, type ParticipantInfo, type PubSubHandle, type PubSubHandleForTopic, type PubSubMessage, type PubSubTopic, type PubSubTopicConfig, type Reaction, type RecordingInfo, type SFUConnectionState, type TrackInfo, VideoSDKCore, useLocalParticipant, useMeeting, useMeetingContext, useMeetingPreview, useParticipants, usePubSub, useRemoteMedia };
package/dist/index.d.ts CHANGED
@@ -59,6 +59,34 @@ type ChatMessage = {
59
59
  } | null;
60
60
  target?: string | null;
61
61
  };
62
+ type PubSubMessage<T = unknown> = {
63
+ id: string;
64
+ topic: PubSubTopic;
65
+ sender_id: string;
66
+ sender_name?: string | null;
67
+ timestamp: number;
68
+ data: T;
69
+ };
70
+ type PubSubTopicConfig = {
71
+ SECURE_CHAT: {
72
+ publish: ChatInput;
73
+ message: ChatMessage;
74
+ };
75
+ REACTION: {
76
+ publish: {
77
+ emoji: string;
78
+ };
79
+ message: {
80
+ emoji: string;
81
+ };
82
+ };
83
+ };
84
+ type PubSubTopic = keyof PubSubTopicConfig;
85
+ type PubSubHandle<TPublish = unknown, TMessage = TPublish> = {
86
+ messages: PubSubMessage<TMessage>[];
87
+ publish: (data: TPublish) => void;
88
+ };
89
+ type PubSubHandleForTopic<T extends PubSubTopic> = PubSubHandle<PubSubTopicConfig[T]["publish"], PubSubTopicConfig[T]["message"]>;
62
90
  type Participant = {
63
91
  id: string;
64
92
  name?: string;
@@ -97,7 +125,6 @@ type MeetingConfig = {
97
125
  videoMuted?: boolean;
98
126
  token?: string;
99
127
  };
100
- type PubSubTopic = "SECURE_CHAT" | "REACTION";
101
128
  type RecordingInfo = {
102
129
  recording_id: string;
103
130
  started_at?: string;
@@ -241,6 +268,15 @@ declare class VideoSDKCore {
241
268
  }>;
242
269
  sendChatMessage(payload: ChatInput): void;
243
270
  sendReaction(reaction: string): void;
271
+ /**
272
+ * Generic PubSub publishing entry point.
273
+ *
274
+ * The public SDK exposes one PubSub API for all topics. The current SFU
275
+ * protocol still has dedicated wire messages for chat and reactions, so
276
+ * this method is the compatibility bridge. The application does not need
277
+ * to know about those wire-level message types.
278
+ */
279
+ publishPubSub<T extends PubSubTopic>(topic: T, data: PubSubTopicConfig[T]["publish"]): void;
244
280
  private cleanupRemoteParticipant;
245
281
  disconnect(): Promise<void>;
246
282
  private performDisconnect;
@@ -263,10 +299,6 @@ interface ParticipantInfo {
263
299
  [key: string]: any;
264
300
  }
265
301
 
266
- type PubSubHandle = {
267
- messages: ChatMessage[];
268
- publish: (input: ChatInput) => void;
269
- };
270
302
  type MeetingContextValue = {
271
303
  sdk: VideoSDKCore;
272
304
  join: (config?: Omit<MeetingConfig, "participantId">) => Promise<void>;
@@ -296,7 +328,8 @@ type MeetingContextValue = {
296
328
  presenterId: string | null;
297
329
  activeSpeakerIds: string[];
298
330
  recording: RecordingInfo | null;
299
- usePubSub: (topic: PubSubTopic) => PubSubHandle;
331
+ usePubSub: <T extends PubSubTopic>(topic: T) => PubSubHandleForTopic<T>;
332
+ onPubSubMessage: <T extends PubSubTopic>(topic: T, cb: (message: PubSubMessage<PubSubTopicConfig[T]["message"]>) => void) => () => void;
300
333
  approveJoinRequest: (requestId: string) => void;
301
334
  rejectJoinRequest: (requestId: string) => void;
302
335
  startRecording: () => Promise<void>;
@@ -358,10 +391,8 @@ declare const useMeeting: (handlers?: {
358
391
  presenterId: string | null;
359
392
  activeSpeakerIds: string[];
360
393
  recording: RecordingInfo | null;
361
- usePubSub: (topic: PubSubTopic) => {
362
- messages: ChatMessage[];
363
- publish: (input: ChatInput) => void;
364
- };
394
+ usePubSub: <T extends PubSubTopic>(topic: T) => PubSubHandleForTopic<T>;
395
+ onPubSubMessage: <T extends PubSubTopic>(topic: T, cb: (message: PubSubMessage<PubSubTopicConfig[T]["message"]>) => void) => () => void;
365
396
  approveJoinRequest: (requestId: string) => void;
366
397
  rejectJoinRequest: (requestId: string) => void;
367
398
  startRecording: () => Promise<void>;
@@ -456,4 +487,8 @@ declare class ActiveSpeakerDetector {
456
487
  destroy(): Promise<void>;
457
488
  }
458
489
 
459
- export { ActiveSpeakerDetector, type ChatInput, type MeetingConfig, MeetingProvider, MeetingState, type Participant, type ParticipantInfo, type Reaction, type RecordingInfo, type SFUConnectionState, type TrackInfo, VideoSDKCore, useLocalParticipant, useMeeting, useMeetingContext, useMeetingPreview, useParticipants, useRemoteMedia };
490
+ declare function usePubSub<T extends PubSubTopic>(topic: T, options?: {
491
+ onMessageReceived?: (message: PubSubMessage<PubSubTopicConfig[T]["message"]>) => void;
492
+ }): PubSubHandleForTopic<T>;
493
+
494
+ export { ActiveSpeakerDetector, type ChatInput, type MeetingConfig, MeetingProvider, MeetingState, type Participant, type ParticipantInfo, type PubSubHandle, type PubSubHandleForTopic, type PubSubMessage, type PubSubTopic, type PubSubTopicConfig, type Reaction, type RecordingInfo, type SFUConnectionState, type TrackInfo, VideoSDKCore, useLocalParticipant, useMeeting, useMeetingContext, useMeetingPreview, useParticipants, usePubSub, useRemoteMedia };
package/dist/index.js CHANGED
@@ -29,6 +29,7 @@ __export(index_exports, {
29
29
  useMeetingContext: () => useMeetingContext,
30
30
  useMeetingPreview: () => useMeetingPreview,
31
31
  useParticipants: () => useParticipants,
32
+ usePubSub: () => usePubSub,
32
33
  useRemoteMedia: () => useRemoteMedia
33
34
  });
34
35
  module.exports = __toCommonJS(index_exports);
@@ -2738,6 +2739,28 @@ var VideoSDKCore = class {
2738
2739
  }
2739
2740
  this.sfuClient.sendReaction(reaction);
2740
2741
  }
2742
+ /**
2743
+ * Generic PubSub publishing entry point.
2744
+ *
2745
+ * The public SDK exposes one PubSub API for all topics. The current SFU
2746
+ * protocol still has dedicated wire messages for chat and reactions, so
2747
+ * this method is the compatibility bridge. The application does not need
2748
+ * to know about those wire-level message types.
2749
+ */
2750
+ publishPubSub(topic, data) {
2751
+ switch (topic) {
2752
+ case "SECURE_CHAT":
2753
+ this.sendChatMessage(data);
2754
+ return;
2755
+ case "REACTION":
2756
+ this.sendReaction(data.emoji);
2757
+ return;
2758
+ default: {
2759
+ const exhaustive = topic;
2760
+ throw new Error(`Unsupported PubSub topic: ${exhaustive}`);
2761
+ }
2762
+ }
2763
+ }
2741
2764
  // CLEANUP
2742
2765
  cleanupRemoteParticipant(participantId) {
2743
2766
  this.activeSpeakerDetector.removeParticipant(participantId);
@@ -2825,6 +2848,10 @@ var MeetingProvider = ({
2825
2848
  const recordingStartedListeners = (0, import_react2.useRef)(/* @__PURE__ */ new Set());
2826
2849
  const recordingStoppedListeners = (0, import_react2.useRef)(/* @__PURE__ */ new Set());
2827
2850
  const reactionListeners = (0, import_react2.useRef)(/* @__PURE__ */ new Set());
2851
+ const pubSubListeners = (0, import_react2.useRef)(
2852
+ /* @__PURE__ */ new Map()
2853
+ );
2854
+ const [reactionPubSubMessages, setReactionPubSubMessages] = (0, import_react2.useState)([]);
2828
2855
  const activeSpeakerListeners = (0, import_react2.useRef)(
2829
2856
  /* @__PURE__ */ new Set()
2830
2857
  );
@@ -2858,8 +2885,43 @@ var MeetingProvider = ({
2858
2885
  onRecordingStopped: (recording2) => {
2859
2886
  recordingStoppedListeners.current.forEach((fn) => fn(recording2));
2860
2887
  },
2888
+ onChatMessage: (message) => {
2889
+ const msg = {
2890
+ id: message.id,
2891
+ text: message.text,
2892
+ sender_id: message.sender_id,
2893
+ sender_name: message.sender_name,
2894
+ timestamp: Number(message.timestamp),
2895
+ reply_to: message.reply_to ?? null,
2896
+ target: message.target ?? null
2897
+ };
2898
+ const pubSubMessage = {
2899
+ id: msg.id,
2900
+ topic: "SECURE_CHAT",
2901
+ sender_id: msg.sender_id,
2902
+ sender_name: msg.sender_name,
2903
+ timestamp: msg.timestamp,
2904
+ data: msg
2905
+ };
2906
+ pubSubListeners.current.get("SECURE_CHAT")?.forEach((fn) => fn(pubSubMessage));
2907
+ },
2861
2908
  onReaction: (reaction) => {
2862
2909
  reactionListeners.current.forEach((fn) => fn(reaction));
2910
+ const timestamp = typeof reaction.timestamp === "number" ? reaction.timestamp : Date.parse(reaction.timestamp);
2911
+ const message = {
2912
+ id: reaction.id,
2913
+ topic: "REACTION",
2914
+ sender_id: reaction.participant_id,
2915
+ sender_name: reaction.sender_name,
2916
+ timestamp,
2917
+ data: {
2918
+ emoji: reaction.emoji
2919
+ }
2920
+ };
2921
+ setReactionPubSubMessages(
2922
+ (previous) => [...previous, message].slice(-50)
2923
+ );
2924
+ pubSubListeners.current.get("REACTION")?.forEach((fn) => fn(message));
2863
2925
  },
2864
2926
  onConnectionStateChanged: (state) => {
2865
2927
  connectionStateListeners.current.forEach(
@@ -2922,12 +2984,48 @@ var MeetingProvider = ({
2922
2984
  activeSpeakerIds,
2923
2985
  recording,
2924
2986
  usePubSub: (topic) => {
2925
- if (topic !== "SECURE_CHAT") {
2926
- throw new Error(`Unsupported PubSub argument: "${topic}"`);
2987
+ if (topic === "SECURE_CHAT") {
2988
+ const chatMessages = messages.map((message) => ({
2989
+ id: message.id,
2990
+ topic: "SECURE_CHAT",
2991
+ sender_id: message.sender_id,
2992
+ sender_name: message.sender_name,
2993
+ timestamp: message.timestamp,
2994
+ data: message
2995
+ }));
2996
+ return {
2997
+ messages: chatMessages,
2998
+ publish: ((data) => {
2999
+ sdk.publishPubSub("SECURE_CHAT", data);
3000
+ })
3001
+ };
2927
3002
  }
2928
- return {
2929
- messages: sdk.state.getChatMessages(),
2930
- publish: sdk.sendChatMessage.bind(sdk)
3003
+ if (topic === "REACTION") {
3004
+ return {
3005
+ messages: reactionPubSubMessages,
3006
+ publish: ((data) => {
3007
+ if (!data?.emoji) {
3008
+ console.warn("[PubSub] REACTION requires an emoji");
3009
+ return;
3010
+ }
3011
+ sdk.publishPubSub("REACTION", data);
3012
+ })
3013
+ };
3014
+ }
3015
+ throw new Error(`Unsupported PubSub topic: "${topic}"`);
3016
+ },
3017
+ onPubSubMessage: (topic, cb) => {
3018
+ let listeners = pubSubListeners.current.get(topic);
3019
+ if (!listeners) {
3020
+ listeners = /* @__PURE__ */ new Set();
3021
+ pubSubListeners.current.set(topic, listeners);
3022
+ }
3023
+ listeners.add(cb);
3024
+ return () => {
3025
+ listeners?.delete(cb);
3026
+ if (listeners?.size === 0) {
3027
+ pubSubListeners.current.delete(topic);
3028
+ }
2931
3029
  };
2932
3030
  },
2933
3031
  approveJoinRequest: sdk.approveJoinRequest.bind(sdk),
@@ -2996,7 +3094,8 @@ var MeetingProvider = ({
2996
3094
  messages,
2997
3095
  presenterId,
2998
3096
  recording,
2999
- activeSpeakerIds
3097
+ activeSpeakerIds,
3098
+ reactionPubSubMessages
3000
3099
  ]);
3001
3100
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MeetingContext.Provider, { value, children });
3002
3101
  };
@@ -3226,6 +3325,20 @@ function useMeetingPreview(roomId, participantId) {
3226
3325
  error
3227
3326
  };
3228
3327
  }
3328
+
3329
+ // src/react/usePubSub.ts
3330
+ var import_react8 = require("react");
3331
+ function usePubSub(topic, options) {
3332
+ const ctx = useMeetingContext();
3333
+ (0, import_react8.useEffect)(() => {
3334
+ if (!options?.onMessageReceived) return;
3335
+ return ctx.onPubSubMessage(
3336
+ topic,
3337
+ options.onMessageReceived
3338
+ );
3339
+ }, [ctx, topic, options?.onMessageReceived]);
3340
+ return ctx.usePubSub(topic);
3341
+ }
3229
3342
  // Annotate the CommonJS export names for ESM import in node:
3230
3343
  0 && (module.exports = {
3231
3344
  ActiveSpeakerDetector,
@@ -3237,6 +3350,7 @@ function useMeetingPreview(roomId, participantId) {
3237
3350
  useMeetingContext,
3238
3351
  useMeetingPreview,
3239
3352
  useParticipants,
3353
+ usePubSub,
3240
3354
  useRemoteMedia
3241
3355
  });
3242
3356
  //# sourceMappingURL=index.js.map