@defcomm/meetingsdk 0.4.4 → 0.4.6
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 +40 -14
- package/dist/index.d.ts +40 -14
- package/dist/index.js +123 -81
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +135 -93
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/react/useLocalParticipant.tsx
|
|
2
|
-
import { useCallback, useEffect as useEffect2, useRef as useRef2, useState as
|
|
2
|
+
import { useCallback, useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
|
|
3
3
|
|
|
4
4
|
// src/react/MeetingProvider.tsx
|
|
5
|
-
import { createContext, useContext, useMemo, useRef } from "react";
|
|
5
|
+
import { createContext, useContext, useMemo, useRef, useState as useState2 } from "react";
|
|
6
6
|
|
|
7
7
|
// src/config/ws.ts
|
|
8
8
|
var SDK_CONFIG = {
|
|
@@ -368,6 +368,9 @@ var SFUClient = class {
|
|
|
368
368
|
this.publisherRevision = 0;
|
|
369
369
|
this.screenShareGeneration = 0;
|
|
370
370
|
this.currentParticipantId = null;
|
|
371
|
+
// Provider/application token used for authenticated REST calls.
|
|
372
|
+
this.authToken = null;
|
|
373
|
+
// Room/SFU token returned by /token and used for the WebSocket.
|
|
371
374
|
this.token = null;
|
|
372
375
|
this.room = null;
|
|
373
376
|
this.resumeToken = null;
|
|
@@ -408,6 +411,7 @@ var SFUClient = class {
|
|
|
408
411
|
this.apiBase = options.apiBase || "https://api.example.com/api";
|
|
409
412
|
this.wsBase = options.wsBase || "wss://api.example.com/ws";
|
|
410
413
|
this.participantId = options.participantId || this.createId();
|
|
414
|
+
this.authToken = options.token ?? null;
|
|
411
415
|
this.onStateChange = options.onStateChange || (() => {
|
|
412
416
|
});
|
|
413
417
|
this.onParticipantJoined = options.onParticipantJoined || (() => {
|
|
@@ -531,9 +535,14 @@ var SFUClient = class {
|
|
|
531
535
|
return (++this.requestId).toString();
|
|
532
536
|
}
|
|
533
537
|
async request(url, options = {}) {
|
|
538
|
+
const headers = new Headers(options.headers);
|
|
539
|
+
headers.set("Content-Type", "application/json");
|
|
540
|
+
if (this.authToken) {
|
|
541
|
+
headers.set("Authorization", `Bearer ${this.authToken}`);
|
|
542
|
+
}
|
|
534
543
|
const res = await fetch(url, {
|
|
535
|
-
|
|
536
|
-
|
|
544
|
+
...options,
|
|
545
|
+
headers
|
|
537
546
|
});
|
|
538
547
|
if (!res.ok) {
|
|
539
548
|
let body = {};
|
|
@@ -541,7 +550,9 @@ var SFUClient = class {
|
|
|
541
550
|
body = await res.json();
|
|
542
551
|
} catch {
|
|
543
552
|
}
|
|
544
|
-
throw new Error(
|
|
553
|
+
throw new Error(
|
|
554
|
+
body.message || `Request failed: ${res.status} ${res.statusText}`
|
|
555
|
+
);
|
|
545
556
|
}
|
|
546
557
|
return res.json();
|
|
547
558
|
}
|
|
@@ -1945,6 +1956,7 @@ var VideoSDKCore = class {
|
|
|
1945
1956
|
}
|
|
1946
1957
|
});
|
|
1947
1958
|
this.myId = options.participantId;
|
|
1959
|
+
this.sfuClient = this.createSFUClient(options.token);
|
|
1948
1960
|
}
|
|
1949
1961
|
emitError(code, message, raw, recoverable = true) {
|
|
1950
1962
|
const err = {
|
|
@@ -2009,36 +2021,16 @@ var VideoSDKCore = class {
|
|
|
2009
2021
|
}
|
|
2010
2022
|
// ROOM MANAGEMENT
|
|
2011
2023
|
async createRoom(input) {
|
|
2012
|
-
|
|
2013
|
-
apiBase: this.apiBase,
|
|
2014
|
-
wsBase: this.wsBase,
|
|
2015
|
-
participantId: this.myId
|
|
2016
|
-
});
|
|
2017
|
-
return client.createRoom(input);
|
|
2024
|
+
return this.sfuClient.createRoom(input);
|
|
2018
2025
|
}
|
|
2019
2026
|
async getRoom(roomCode) {
|
|
2020
|
-
|
|
2021
|
-
apiBase: this.apiBase,
|
|
2022
|
-
wsBase: this.wsBase,
|
|
2023
|
-
participantId: this.myId
|
|
2024
|
-
});
|
|
2025
|
-
return client.getRoom(roomCode);
|
|
2027
|
+
return this.sfuClient.getRoom(roomCode);
|
|
2026
2028
|
}
|
|
2027
2029
|
async getJoinState(roomCode) {
|
|
2028
|
-
|
|
2029
|
-
apiBase: this.apiBase,
|
|
2030
|
-
wsBase: this.wsBase,
|
|
2031
|
-
participantId: this.myId
|
|
2032
|
-
});
|
|
2033
|
-
return client.getJoinState(roomCode);
|
|
2030
|
+
return this.sfuClient.getJoinState(roomCode);
|
|
2034
2031
|
}
|
|
2035
2032
|
async deleteRoom(roomCode) {
|
|
2036
|
-
|
|
2037
|
-
apiBase: this.apiBase,
|
|
2038
|
-
wsBase: this.wsBase,
|
|
2039
|
-
participantId: this.myId
|
|
2040
|
-
});
|
|
2041
|
-
return client.deleteRoom(roomCode);
|
|
2033
|
+
return this.sfuClient.deleteRoom(roomCode);
|
|
2042
2034
|
}
|
|
2043
2035
|
// JOIN
|
|
2044
2036
|
async joinMeeting(config) {
|
|
@@ -2104,26 +2096,36 @@ var VideoSDKCore = class {
|
|
|
2104
2096
|
}
|
|
2105
2097
|
// SFU CONNECTION
|
|
2106
2098
|
async connect(roomId, name) {
|
|
2107
|
-
if (this.sfuClient) {
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2099
|
+
if (!this.sfuClient) {
|
|
2100
|
+
throw new Error("SFU client is not initialized");
|
|
2101
|
+
}
|
|
2102
|
+
const state = this.sfuClient.getConnectionState();
|
|
2103
|
+
if (this.room.id === roomId && (state === "connecting" || state === "joining" || state === "waiting_approval" || state === "connected" || state === "reconnecting")) {
|
|
2104
|
+
console.info("[SDK] Existing SFU connection is active; connect ignored", {
|
|
2105
|
+
roomId,
|
|
2106
|
+
state
|
|
2107
|
+
});
|
|
2108
|
+
return;
|
|
2109
|
+
}
|
|
2110
|
+
if (state !== "idle" && state !== "disconnected") {
|
|
2119
2111
|
throw new Error(
|
|
2120
|
-
`SFU client already
|
|
2112
|
+
`SFU client is already active in state "${state}". Leave the current meeting before joining another room.`
|
|
2121
2113
|
);
|
|
2122
2114
|
}
|
|
2123
|
-
|
|
2115
|
+
this.sfuClient.setLocalStream(this.localStream);
|
|
2116
|
+
await this.sfuClient.getToken(roomId, {
|
|
2117
|
+
displayName: name,
|
|
2118
|
+
participantId: this.myId,
|
|
2119
|
+
audioMuted: !(this.localStream?.getAudioTracks()[0]?.enabled ?? true),
|
|
2120
|
+
videoMuted: !(this.localStream?.getVideoTracks()[0]?.enabled ?? true)
|
|
2121
|
+
});
|
|
2122
|
+
}
|
|
2123
|
+
createSFUClient(token) {
|
|
2124
|
+
return new SFUClient({
|
|
2124
2125
|
apiBase: this.apiBase,
|
|
2125
2126
|
wsBase: this.wsBase,
|
|
2126
2127
|
participantId: this.myId,
|
|
2128
|
+
token,
|
|
2127
2129
|
autoSubscribe: true,
|
|
2128
2130
|
// CONNECTION STATE
|
|
2129
2131
|
onStateChange: (state) => {
|
|
@@ -2462,14 +2464,6 @@ var VideoSDKCore = class {
|
|
|
2462
2464
|
);
|
|
2463
2465
|
}
|
|
2464
2466
|
});
|
|
2465
|
-
this.sfuClient = client;
|
|
2466
|
-
client.setLocalStream(this.localStream);
|
|
2467
|
-
await client.getToken(roomId, {
|
|
2468
|
-
displayName: name,
|
|
2469
|
-
participantId: this.myId,
|
|
2470
|
-
audioMuted: !(this.localStream?.getAudioTracks()[0]?.enabled ?? true),
|
|
2471
|
-
videoMuted: !(this.localStream?.getVideoTracks()[0]?.enabled ?? true)
|
|
2472
|
-
});
|
|
2473
2467
|
}
|
|
2474
2468
|
// SFU STATE
|
|
2475
2469
|
handleSFUState(state) {
|
|
@@ -2703,6 +2697,28 @@ var VideoSDKCore = class {
|
|
|
2703
2697
|
}
|
|
2704
2698
|
this.sfuClient.sendReaction(reaction);
|
|
2705
2699
|
}
|
|
2700
|
+
/**
|
|
2701
|
+
* Generic PubSub publishing entry point.
|
|
2702
|
+
*
|
|
2703
|
+
* The public SDK exposes one PubSub API for all topics. The current SFU
|
|
2704
|
+
* protocol still has dedicated wire messages for chat and reactions, so
|
|
2705
|
+
* this method is the compatibility bridge. The application does not need
|
|
2706
|
+
* to know about those wire-level message types.
|
|
2707
|
+
*/
|
|
2708
|
+
publishPubSub(topic, data) {
|
|
2709
|
+
switch (topic) {
|
|
2710
|
+
case "SECURE_CHAT":
|
|
2711
|
+
this.sendChatMessage(data);
|
|
2712
|
+
return;
|
|
2713
|
+
case "REACTION":
|
|
2714
|
+
this.sendReaction(data.emoji);
|
|
2715
|
+
return;
|
|
2716
|
+
default: {
|
|
2717
|
+
const exhaustive = topic;
|
|
2718
|
+
throw new Error(`Unsupported PubSub topic: ${exhaustive}`);
|
|
2719
|
+
}
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2706
2722
|
// CLEANUP
|
|
2707
2723
|
cleanupRemoteParticipant(participantId) {
|
|
2708
2724
|
this.activeSpeakerDetector.removeParticipant(participantId);
|
|
@@ -2728,10 +2744,8 @@ var VideoSDKCore = class {
|
|
|
2728
2744
|
async performDisconnect() {
|
|
2729
2745
|
this.intentionalDisconnect = true;
|
|
2730
2746
|
this.joinPromise = null;
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
if (client) {
|
|
2734
|
-
await client.leave();
|
|
2747
|
+
if (this.sfuClient) {
|
|
2748
|
+
await this.sfuClient.leave();
|
|
2735
2749
|
}
|
|
2736
2750
|
if (this.localStream) {
|
|
2737
2751
|
this.localStream.getTracks().forEach((track) => track.stop());
|
|
@@ -2793,6 +2807,7 @@ var MeetingProvider = ({
|
|
|
2793
2807
|
const pubSubListeners = useRef(
|
|
2794
2808
|
/* @__PURE__ */ new Map()
|
|
2795
2809
|
);
|
|
2810
|
+
const [reactionPubSubMessages, setReactionPubSubMessages] = useState2([]);
|
|
2796
2811
|
const activeSpeakerListeners = useRef(
|
|
2797
2812
|
/* @__PURE__ */ new Set()
|
|
2798
2813
|
);
|
|
@@ -2802,7 +2817,8 @@ var MeetingProvider = ({
|
|
|
2802
2817
|
if (!sdkRef.current) {
|
|
2803
2818
|
sdkRef.current = new VideoSDKCore(
|
|
2804
2819
|
{
|
|
2805
|
-
participantId: config.participantId
|
|
2820
|
+
participantId: config.participantId,
|
|
2821
|
+
token: config.token
|
|
2806
2822
|
},
|
|
2807
2823
|
{
|
|
2808
2824
|
onError: (err) => {
|
|
@@ -2826,21 +2842,43 @@ var MeetingProvider = ({
|
|
|
2826
2842
|
onRecordingStopped: (recording2) => {
|
|
2827
2843
|
recordingStoppedListeners.current.forEach((fn) => fn(recording2));
|
|
2828
2844
|
},
|
|
2845
|
+
onChatMessage: (message) => {
|
|
2846
|
+
const msg = {
|
|
2847
|
+
id: message.id,
|
|
2848
|
+
text: message.text,
|
|
2849
|
+
sender_id: message.sender_id,
|
|
2850
|
+
sender_name: message.sender_name,
|
|
2851
|
+
timestamp: Number(message.timestamp),
|
|
2852
|
+
reply_to: message.reply_to ?? null,
|
|
2853
|
+
target: message.target ?? null
|
|
2854
|
+
};
|
|
2855
|
+
const pubSubMessage = {
|
|
2856
|
+
id: msg.id,
|
|
2857
|
+
topic: "SECURE_CHAT",
|
|
2858
|
+
sender_id: msg.sender_id,
|
|
2859
|
+
sender_name: msg.sender_name,
|
|
2860
|
+
timestamp: msg.timestamp,
|
|
2861
|
+
data: msg
|
|
2862
|
+
};
|
|
2863
|
+
pubSubListeners.current.get("SECURE_CHAT")?.forEach((fn) => fn(pubSubMessage));
|
|
2864
|
+
},
|
|
2829
2865
|
onReaction: (reaction) => {
|
|
2830
2866
|
reactionListeners.current.forEach((fn) => fn(reaction));
|
|
2831
|
-
const
|
|
2832
|
-
if (!listeners) return;
|
|
2867
|
+
const timestamp = typeof reaction.timestamp === "number" ? reaction.timestamp : Date.parse(reaction.timestamp);
|
|
2833
2868
|
const message = {
|
|
2834
2869
|
id: reaction.id,
|
|
2835
2870
|
topic: "REACTION",
|
|
2836
2871
|
sender_id: reaction.participant_id,
|
|
2837
2872
|
sender_name: reaction.sender_name,
|
|
2838
|
-
timestamp
|
|
2873
|
+
timestamp,
|
|
2839
2874
|
data: {
|
|
2840
2875
|
emoji: reaction.emoji
|
|
2841
2876
|
}
|
|
2842
2877
|
};
|
|
2843
|
-
|
|
2878
|
+
setReactionPubSubMessages(
|
|
2879
|
+
(previous) => [...previous, message].slice(-50)
|
|
2880
|
+
);
|
|
2881
|
+
pubSubListeners.current.get("REACTION")?.forEach((fn) => fn(message));
|
|
2844
2882
|
},
|
|
2845
2883
|
onConnectionStateChanged: (state) => {
|
|
2846
2884
|
connectionStateListeners.current.forEach(
|
|
@@ -2903,32 +2941,32 @@ var MeetingProvider = ({
|
|
|
2903
2941
|
activeSpeakerIds,
|
|
2904
2942
|
recording,
|
|
2905
2943
|
usePubSub: (topic) => {
|
|
2944
|
+
if (topic === "SECURE_CHAT") {
|
|
2945
|
+
const chatMessages = messages.map((message) => ({
|
|
2946
|
+
id: message.id,
|
|
2947
|
+
topic: "SECURE_CHAT",
|
|
2948
|
+
sender_id: message.sender_id,
|
|
2949
|
+
sender_name: message.sender_name,
|
|
2950
|
+
timestamp: message.timestamp,
|
|
2951
|
+
data: message
|
|
2952
|
+
}));
|
|
2953
|
+
return {
|
|
2954
|
+
messages: chatMessages,
|
|
2955
|
+
publish: ((data) => {
|
|
2956
|
+
sdk.publishPubSub("SECURE_CHAT", data);
|
|
2957
|
+
})
|
|
2958
|
+
};
|
|
2959
|
+
}
|
|
2906
2960
|
if (topic === "REACTION") {
|
|
2907
2961
|
return {
|
|
2908
|
-
messages:
|
|
2909
|
-
publish: (data) => {
|
|
2910
|
-
|
|
2911
|
-
if (!reaction?.emoji) {
|
|
2962
|
+
messages: reactionPubSubMessages,
|
|
2963
|
+
publish: ((data) => {
|
|
2964
|
+
if (!data?.emoji) {
|
|
2912
2965
|
console.warn("[PubSub] REACTION requires an emoji");
|
|
2913
2966
|
return;
|
|
2914
2967
|
}
|
|
2915
|
-
sdk.
|
|
2916
|
-
}
|
|
2917
|
-
};
|
|
2918
|
-
}
|
|
2919
|
-
if (topic === "SECURE_CHAT") {
|
|
2920
|
-
return {
|
|
2921
|
-
messages: sdk.state.getChatMessages().map((message) => ({
|
|
2922
|
-
id: message.id,
|
|
2923
|
-
topic: "SECURE_CHAT",
|
|
2924
|
-
sender_id: message.sender_id,
|
|
2925
|
-
sender_name: message.sender_name,
|
|
2926
|
-
timestamp: message.timestamp,
|
|
2927
|
-
data: message
|
|
2928
|
-
})),
|
|
2929
|
-
publish: (data) => {
|
|
2930
|
-
sdk.sendChatMessage(data);
|
|
2931
|
-
}
|
|
2968
|
+
sdk.publishPubSub("REACTION", data);
|
|
2969
|
+
})
|
|
2932
2970
|
};
|
|
2933
2971
|
}
|
|
2934
2972
|
throw new Error(`Unsupported PubSub topic: "${topic}"`);
|
|
@@ -3013,7 +3051,8 @@ var MeetingProvider = ({
|
|
|
3013
3051
|
messages,
|
|
3014
3052
|
presenterId,
|
|
3015
3053
|
recording,
|
|
3016
|
-
activeSpeakerIds
|
|
3054
|
+
activeSpeakerIds,
|
|
3055
|
+
reactionPubSubMessages
|
|
3017
3056
|
]);
|
|
3018
3057
|
return /* @__PURE__ */ jsx(MeetingContext.Provider, { value, children });
|
|
3019
3058
|
};
|
|
@@ -3027,7 +3066,7 @@ var useMeetingContext = () => {
|
|
|
3027
3066
|
// src/react/useLocalParticipant.tsx
|
|
3028
3067
|
var useLocalParticipant = () => {
|
|
3029
3068
|
const { sdk } = useMeetingContext();
|
|
3030
|
-
const [localParticipant, setLocalParticipant] =
|
|
3069
|
+
const [localParticipant, setLocalParticipant] = useState3(
|
|
3031
3070
|
() => {
|
|
3032
3071
|
const current = sdk.state.localParticipant;
|
|
3033
3072
|
return current && current.id ? current : null;
|
|
@@ -3116,10 +3155,10 @@ var useMeeting = (handlers) => {
|
|
|
3116
3155
|
};
|
|
3117
3156
|
|
|
3118
3157
|
// src/react/useParticipants.ts
|
|
3119
|
-
import { useEffect as useEffect4, useState as
|
|
3158
|
+
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
3120
3159
|
var useParticipants = () => {
|
|
3121
3160
|
const { sdk } = useMeetingContext();
|
|
3122
|
-
const [participants, setParticipants] =
|
|
3161
|
+
const [participants, setParticipants] = useState4(
|
|
3123
3162
|
() => sdk.state.getParticipants()
|
|
3124
3163
|
);
|
|
3125
3164
|
useEffect4(() => {
|
|
@@ -3134,12 +3173,12 @@ var useParticipants = () => {
|
|
|
3134
3173
|
};
|
|
3135
3174
|
|
|
3136
3175
|
// src/react/useRemoteMedia.ts
|
|
3137
|
-
import { useEffect as useEffect5, useRef as useRef3, useState as
|
|
3176
|
+
import { useEffect as useEffect5, useRef as useRef3, useState as useState5 } from "react";
|
|
3138
3177
|
var useRemoteMedia = (participantId) => {
|
|
3139
3178
|
const { sdk } = useMeetingContext();
|
|
3140
3179
|
const videoRef = useRef3(null);
|
|
3141
3180
|
const audioRef = useRef3(null);
|
|
3142
|
-
const [participant, setParticipant] =
|
|
3181
|
+
const [participant, setParticipant] = useState5(
|
|
3143
3182
|
() => sdk.state.getParticipant(participantId) || null
|
|
3144
3183
|
);
|
|
3145
3184
|
useEffect5(() => {
|
|
@@ -3175,12 +3214,12 @@ var useRemoteMedia = (participantId) => {
|
|
|
3175
3214
|
};
|
|
3176
3215
|
|
|
3177
3216
|
// src/react/useMeetingPreview.ts
|
|
3178
|
-
import { useEffect as useEffect6, useState as
|
|
3217
|
+
import { useEffect as useEffect6, useState as useState6 } from "react";
|
|
3179
3218
|
function useMeetingPreview(roomId, participantId) {
|
|
3180
|
-
const [room, setRoom] =
|
|
3181
|
-
const [error, setError] =
|
|
3182
|
-
const [isConnected, setIsConnected] =
|
|
3183
|
-
const [isLoading, setIsLoading] =
|
|
3219
|
+
const [room, setRoom] = useState6(null);
|
|
3220
|
+
const [error, setError] = useState6(null);
|
|
3221
|
+
const [isConnected, setIsConnected] = useState6(false);
|
|
3222
|
+
const [isLoading, setIsLoading] = useState6(true);
|
|
3184
3223
|
useEffect6(() => {
|
|
3185
3224
|
if (!roomId) {
|
|
3186
3225
|
setIsLoading(false);
|
|
@@ -3250,7 +3289,10 @@ function usePubSub(topic, options) {
|
|
|
3250
3289
|
const ctx = useMeetingContext();
|
|
3251
3290
|
useEffect7(() => {
|
|
3252
3291
|
if (!options?.onMessageReceived) return;
|
|
3253
|
-
return ctx.onPubSubMessage(
|
|
3292
|
+
return ctx.onPubSubMessage(
|
|
3293
|
+
topic,
|
|
3294
|
+
options.onMessageReceived
|
|
3295
|
+
);
|
|
3254
3296
|
}, [ctx, topic, options?.onMessageReceived]);
|
|
3255
3297
|
return ctx.usePubSub(topic);
|
|
3256
3298
|
}
|