vg-x07df 1.8.1 → 1.8.3
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/channel/index.cjs +356 -58
- package/dist/channel/index.cjs.map +1 -1
- package/dist/channel/index.d.cts +73 -4
- package/dist/channel/index.d.ts +73 -4
- package/dist/channel/index.mjs +354 -59
- package/dist/channel/index.mjs.map +1 -1
- package/dist/index.cjs +164 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.mjs +165 -4
- package/dist/index.mjs.map +1 -1
- package/dist/livekit/index.cjs +4 -0
- package/dist/livekit/index.d.cts +1 -1
- package/dist/livekit/index.d.ts +1 -1
- package/dist/livekit/index.mjs +1 -1
- package/dist/{types-CWNlFnPU.d.cts → types-DbGItZmC.d.cts} +24 -1
- package/dist/{types-CWNlFnPU.d.ts → types-DbGItZmC.d.ts} +24 -1
- package/dist/utils/index.cjs +2 -2
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.mjs +2 -2
- package/dist/utils/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/channel/index.cjs
CHANGED
|
@@ -468,37 +468,29 @@ var ChatService = class {
|
|
|
468
468
|
this.room.registerTextStreamHandler(
|
|
469
469
|
"chat:v1",
|
|
470
470
|
async (reader, participantInfo) => {
|
|
471
|
-
console.log("Got here: chat:v1", participantInfo.identity);
|
|
472
471
|
try {
|
|
473
472
|
const text = await reader.readAll();
|
|
474
|
-
console.log("Got here: chat:v1", text);
|
|
473
|
+
console.log("Got here: chat:v1", text, participantInfo.identity);
|
|
475
474
|
this.handleIncomingMessage(text);
|
|
476
475
|
} catch (error) {
|
|
477
476
|
logger.error("Error reading text stream", error);
|
|
478
477
|
}
|
|
479
478
|
}
|
|
480
479
|
);
|
|
481
|
-
this.room.registerByteStreamHandler(
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
Topic: ${info.topic}
|
|
494
|
-
Timestamp: ${info.timestamp}
|
|
495
|
-
ID: ${info.id}
|
|
496
|
-
Size: ${info.size}`
|
|
497
|
-
);
|
|
498
|
-
} catch (error) {
|
|
499
|
-
logger.error("Error reading file stream", error);
|
|
480
|
+
this.room.registerByteStreamHandler(
|
|
481
|
+
"chat:v1",
|
|
482
|
+
async (reader, participantInfo) => {
|
|
483
|
+
try {
|
|
484
|
+
const info = reader.info;
|
|
485
|
+
const filename = info.name;
|
|
486
|
+
const parts = (await reader.readAll()).map((chunk) => chunk.slice());
|
|
487
|
+
const fileBlob = new Blob(parts, { type: info.mimeType });
|
|
488
|
+
this.handleIncomingFile(fileBlob, filename, info.mimeType);
|
|
489
|
+
} catch (error) {
|
|
490
|
+
logger.error("Error reading file stream", error);
|
|
491
|
+
}
|
|
500
492
|
}
|
|
501
|
-
|
|
493
|
+
);
|
|
502
494
|
this.isSubscribed = true;
|
|
503
495
|
}
|
|
504
496
|
unsubscribe() {
|
|
@@ -517,7 +509,6 @@ var ChatService = class {
|
|
|
517
509
|
return;
|
|
518
510
|
}
|
|
519
511
|
if (content.length === 0 && typeof file !== "undefined") {
|
|
520
|
-
console.log("file present", typeof file);
|
|
521
512
|
content = file.name;
|
|
522
513
|
}
|
|
523
514
|
const validation = validateContent(content);
|
|
@@ -566,7 +557,6 @@ var ChatService = class {
|
|
|
566
557
|
await this.room.localParticipant.sendText(JSON.stringify(envelope), {
|
|
567
558
|
topic: "chat:v1"
|
|
568
559
|
});
|
|
569
|
-
console.log("Sent message", entry, envelope);
|
|
570
560
|
if (file) {
|
|
571
561
|
await this.room.localParticipant.sendFile(file, {
|
|
572
562
|
mimeType: file.type,
|
|
@@ -881,13 +871,313 @@ function useChat() {
|
|
|
881
871
|
};
|
|
882
872
|
}
|
|
883
873
|
var defaultState2 = {
|
|
874
|
+
raisedHands: /* @__PURE__ */ new Map(),
|
|
875
|
+
nextOrder: 1
|
|
876
|
+
};
|
|
877
|
+
var useRaiseHandStore = zustand.create()(
|
|
878
|
+
immer.immer((set, get) => ({
|
|
879
|
+
...defaultState2,
|
|
880
|
+
raiseHand: (participantId) => set((state) => {
|
|
881
|
+
if (!state.raisedHands.has(participantId)) {
|
|
882
|
+
state.raisedHands.set(participantId, {
|
|
883
|
+
ts: Date.now(),
|
|
884
|
+
order: state.nextOrder++
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
}),
|
|
888
|
+
lowerHand: (participantId) => set((state) => {
|
|
889
|
+
state.raisedHands.delete(participantId);
|
|
890
|
+
if (state.raisedHands.size === 0) {
|
|
891
|
+
state.nextOrder = 1;
|
|
892
|
+
}
|
|
893
|
+
}),
|
|
894
|
+
lowerAllHands: () => set((state) => {
|
|
895
|
+
state.raisedHands.clear();
|
|
896
|
+
state.nextOrder = 1;
|
|
897
|
+
}),
|
|
898
|
+
isHandRaised: (participantId) => get().raisedHands.has(participantId),
|
|
899
|
+
getRaisedHandOrder: (participantId) => {
|
|
900
|
+
const hand = get().raisedHands.get(participantId);
|
|
901
|
+
return hand?.order ?? null;
|
|
902
|
+
},
|
|
903
|
+
upsertParticipantInfo: (id, info) => {
|
|
904
|
+
},
|
|
905
|
+
clear: () => set(() => ({
|
|
906
|
+
raisedHands: /* @__PURE__ */ new Map(),
|
|
907
|
+
nextOrder: 1
|
|
908
|
+
}))
|
|
909
|
+
}))
|
|
910
|
+
);
|
|
911
|
+
function applyIncomingRaiseHand(envelope) {
|
|
912
|
+
const { raiseHand, lowerHand, lowerAllHands, upsertParticipantInfo } = useRaiseHandStore.getState();
|
|
913
|
+
if (envelope.sender.info) {
|
|
914
|
+
upsertParticipantInfo(envelope.sender.id, envelope.sender.info);
|
|
915
|
+
}
|
|
916
|
+
switch (envelope.payload.action) {
|
|
917
|
+
case "raise": {
|
|
918
|
+
raiseHand(envelope.sender.id);
|
|
919
|
+
break;
|
|
920
|
+
}
|
|
921
|
+
case "lower": {
|
|
922
|
+
const targetId = envelope.payload.targetId || envelope.sender.id;
|
|
923
|
+
lowerHand(targetId);
|
|
924
|
+
break;
|
|
925
|
+
}
|
|
926
|
+
case "lower-all": {
|
|
927
|
+
lowerAllHands();
|
|
928
|
+
break;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// src/channel/raiseHand/service.ts
|
|
934
|
+
var logger2 = createLogger("raise-hand");
|
|
935
|
+
var RaiseHandService = class {
|
|
936
|
+
constructor(room) {
|
|
937
|
+
this.isSubscribed = false;
|
|
938
|
+
this.room = room;
|
|
939
|
+
}
|
|
940
|
+
isRoomReady() {
|
|
941
|
+
if (!this.room) {
|
|
942
|
+
logger2.warn("Room not initialized");
|
|
943
|
+
return false;
|
|
944
|
+
}
|
|
945
|
+
if (this.room.state !== livekitClient.ConnectionState.Connected) {
|
|
946
|
+
logger2.warn("Room not connected", { state: this.room.state });
|
|
947
|
+
return false;
|
|
948
|
+
}
|
|
949
|
+
if (!this.room.localParticipant) {
|
|
950
|
+
logger2.warn("Local participant not available");
|
|
951
|
+
return false;
|
|
952
|
+
}
|
|
953
|
+
return true;
|
|
954
|
+
}
|
|
955
|
+
subscribe() {
|
|
956
|
+
if (this.isSubscribed) return;
|
|
957
|
+
this.room.registerTextStreamHandler("raise-hand:v1", async (reader) => {
|
|
958
|
+
try {
|
|
959
|
+
const text = await reader.readAll();
|
|
960
|
+
this.handleIncoming(text);
|
|
961
|
+
} catch (err) {
|
|
962
|
+
logger2.error("Error reading raise-hand stream", err);
|
|
963
|
+
}
|
|
964
|
+
});
|
|
965
|
+
this.isSubscribed = true;
|
|
966
|
+
logger2.info("RaiseHandService subscribed");
|
|
967
|
+
}
|
|
968
|
+
unsubscribe() {
|
|
969
|
+
this.isSubscribed = false;
|
|
970
|
+
logger2.info("RaiseHandService unsubscribed");
|
|
971
|
+
}
|
|
972
|
+
getLocalParticipantId() {
|
|
973
|
+
return this.room.localParticipant.identity;
|
|
974
|
+
}
|
|
975
|
+
async raiseHand() {
|
|
976
|
+
if (!this.isRoomReady()) {
|
|
977
|
+
useRtcStore.getState().addError({
|
|
978
|
+
code: "RAISE_HAND_ROOM_NOT_READY",
|
|
979
|
+
message: "Cannot raise hand: room not connected",
|
|
980
|
+
timestamp: Date.now()
|
|
981
|
+
});
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
const senderInfo = this.getSenderInfo();
|
|
985
|
+
useRaiseHandStore.getState().raiseHand(senderInfo.id);
|
|
986
|
+
try {
|
|
987
|
+
const envelope = {
|
|
988
|
+
v: 1,
|
|
989
|
+
kind: "raise-hand",
|
|
990
|
+
roomId: this.room.name,
|
|
991
|
+
ts: Date.now(),
|
|
992
|
+
sender: senderInfo,
|
|
993
|
+
payload: {
|
|
994
|
+
action: "raise"
|
|
995
|
+
}
|
|
996
|
+
};
|
|
997
|
+
await this.room.localParticipant.sendText(JSON.stringify(envelope), {
|
|
998
|
+
topic: "raise-hand:v1"
|
|
999
|
+
});
|
|
1000
|
+
logger2.debug("Hand raised");
|
|
1001
|
+
} catch (error) {
|
|
1002
|
+
logger2.error("Failed to raise hand", error);
|
|
1003
|
+
useRtcStore.getState().addError({
|
|
1004
|
+
code: "RAISE_HAND_SEND_FAILED",
|
|
1005
|
+
message: error instanceof Error ? error.message : "Failed to raise hand",
|
|
1006
|
+
timestamp: Date.now()
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
async lowerHand(targetId) {
|
|
1011
|
+
if (!this.isRoomReady()) {
|
|
1012
|
+
useRtcStore.getState().addError({
|
|
1013
|
+
code: "LOWER_HAND_ROOM_NOT_READY",
|
|
1014
|
+
message: "Cannot lower hand: room not connected",
|
|
1015
|
+
timestamp: Date.now()
|
|
1016
|
+
});
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
const senderInfo = this.getSenderInfo();
|
|
1020
|
+
const participantId = targetId || senderInfo.id;
|
|
1021
|
+
useRaiseHandStore.getState().lowerHand(participantId);
|
|
1022
|
+
try {
|
|
1023
|
+
const envelope = {
|
|
1024
|
+
v: 1,
|
|
1025
|
+
kind: "raise-hand",
|
|
1026
|
+
roomId: this.room.name,
|
|
1027
|
+
ts: Date.now(),
|
|
1028
|
+
sender: senderInfo,
|
|
1029
|
+
payload: {
|
|
1030
|
+
action: "lower",
|
|
1031
|
+
targetId: participantId
|
|
1032
|
+
}
|
|
1033
|
+
};
|
|
1034
|
+
await this.room.localParticipant.sendText(JSON.stringify(envelope), {
|
|
1035
|
+
topic: "raise-hand:v1"
|
|
1036
|
+
});
|
|
1037
|
+
logger2.debug("Hand lowered", { targetId: participantId });
|
|
1038
|
+
} catch (error) {
|
|
1039
|
+
logger2.error("Failed to lower hand", error);
|
|
1040
|
+
useRtcStore.getState().addError({
|
|
1041
|
+
code: "LOWER_HAND_SEND_FAILED",
|
|
1042
|
+
message: error instanceof Error ? error.message : "Failed to lower hand",
|
|
1043
|
+
timestamp: Date.now()
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
async lowerAllHands() {
|
|
1048
|
+
if (!this.isRoomReady()) {
|
|
1049
|
+
useRtcStore.getState().addError({
|
|
1050
|
+
code: "LOWER_ALL_HANDS_ROOM_NOT_READY",
|
|
1051
|
+
message: "Cannot lower all hands: room not connected",
|
|
1052
|
+
timestamp: Date.now()
|
|
1053
|
+
});
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
const senderInfo = this.getSenderInfo();
|
|
1057
|
+
useRaiseHandStore.getState().lowerAllHands();
|
|
1058
|
+
try {
|
|
1059
|
+
const envelope = {
|
|
1060
|
+
v: 1,
|
|
1061
|
+
kind: "raise-hand",
|
|
1062
|
+
roomId: this.room.name,
|
|
1063
|
+
ts: Date.now(),
|
|
1064
|
+
sender: senderInfo,
|
|
1065
|
+
payload: {
|
|
1066
|
+
action: "lower-all"
|
|
1067
|
+
}
|
|
1068
|
+
};
|
|
1069
|
+
await this.room.localParticipant.sendText(JSON.stringify(envelope), {
|
|
1070
|
+
topic: "raise-hand:v1"
|
|
1071
|
+
});
|
|
1072
|
+
logger2.debug("All hands lowered");
|
|
1073
|
+
} catch (error) {
|
|
1074
|
+
logger2.error("Failed to lower all hands", error);
|
|
1075
|
+
useRtcStore.getState().addError({
|
|
1076
|
+
code: "LOWER_ALL_HANDS_SEND_FAILED",
|
|
1077
|
+
message: error instanceof Error ? error.message : "Failed to lower all hands",
|
|
1078
|
+
timestamp: Date.now()
|
|
1079
|
+
});
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
handleIncoming(text) {
|
|
1083
|
+
try {
|
|
1084
|
+
const parsed = JSON.parse(text);
|
|
1085
|
+
if (!this.isValidEnvelope(parsed)) {
|
|
1086
|
+
logger2.warn("Invalid raise-hand envelope received", parsed);
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
if (parsed.sender.id === this.getLocalParticipantId()) {
|
|
1090
|
+
logger2.debug("Ignoring self-echo raise-hand message");
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
applyIncomingRaiseHand(parsed);
|
|
1094
|
+
logger2.debug("Raise-hand message received", {
|
|
1095
|
+
action: parsed.payload.action
|
|
1096
|
+
});
|
|
1097
|
+
} catch (error) {
|
|
1098
|
+
logger2.error("Error parsing incoming raise-hand message", error);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
isValidEnvelope(e) {
|
|
1102
|
+
return e && e.v === 1 && e.kind === "raise-hand" && typeof e.roomId === "string" && e.roomId === this.room.name && typeof e.ts === "number" && e.ts > 0 && typeof e.sender?.id === "string" && typeof e.payload?.action === "string" && ["raise", "lower", "lower-all"].includes(e.payload.action);
|
|
1103
|
+
}
|
|
1104
|
+
getSenderInfo() {
|
|
1105
|
+
const localParticipant = this.room.localParticipant;
|
|
1106
|
+
const sender = {
|
|
1107
|
+
id: localParticipant.identity
|
|
1108
|
+
};
|
|
1109
|
+
if (localParticipant.metadata) {
|
|
1110
|
+
try {
|
|
1111
|
+
sender.info = JSON.parse(
|
|
1112
|
+
localParticipant.metadata
|
|
1113
|
+
);
|
|
1114
|
+
} catch {
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
return sender;
|
|
1118
|
+
}
|
|
1119
|
+
};
|
|
1120
|
+
var logger3 = createLogger("raise-hand:hook");
|
|
1121
|
+
function useRaiseHand() {
|
|
1122
|
+
const service = useFeatureService("raise-hand");
|
|
1123
|
+
const raisedHands = useRaiseHandStore((state) => state.raisedHands);
|
|
1124
|
+
const isHandRaised = useRaiseHandStore((state) => state.isHandRaised);
|
|
1125
|
+
const getRaisedHandOrder = useRaiseHandStore(
|
|
1126
|
+
(state) => state.getRaisedHandOrder
|
|
1127
|
+
);
|
|
1128
|
+
const raiseHand = react.useCallback(async () => {
|
|
1129
|
+
if (!service) {
|
|
1130
|
+
logger3.error("Cannot raise hand: service not ready");
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
1133
|
+
return service.raiseHand();
|
|
1134
|
+
}, [service]);
|
|
1135
|
+
const lowerHand = react.useCallback(
|
|
1136
|
+
async (participantId) => {
|
|
1137
|
+
if (!service) {
|
|
1138
|
+
logger3.error("Cannot lower hand: service not ready");
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
return service.lowerHand(participantId);
|
|
1142
|
+
},
|
|
1143
|
+
[service]
|
|
1144
|
+
);
|
|
1145
|
+
const lowerAllHands = react.useCallback(async () => {
|
|
1146
|
+
if (!service) {
|
|
1147
|
+
logger3.error("Cannot lower all hands: service not ready");
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1150
|
+
return service.lowerAllHands();
|
|
1151
|
+
}, [service]);
|
|
1152
|
+
const getRaisedHands = react.useCallback(() => {
|
|
1153
|
+
const hands = [];
|
|
1154
|
+
for (const [participantId, hand] of raisedHands.entries()) {
|
|
1155
|
+
hands.push({
|
|
1156
|
+
participantId,
|
|
1157
|
+
order: hand.order,
|
|
1158
|
+
ts: hand.ts
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
return hands.sort((a, b) => a.order - b.order);
|
|
1162
|
+
}, [raisedHands]);
|
|
1163
|
+
return {
|
|
1164
|
+
raiseHand,
|
|
1165
|
+
lowerHand,
|
|
1166
|
+
lowerAllHands,
|
|
1167
|
+
isHandRaised,
|
|
1168
|
+
getRaisedHandOrder,
|
|
1169
|
+
getRaisedHands,
|
|
1170
|
+
isReady: !!service
|
|
1171
|
+
};
|
|
1172
|
+
}
|
|
1173
|
+
var defaultState3 = {
|
|
884
1174
|
reactions: /* @__PURE__ */ new Map(),
|
|
885
1175
|
participantCache: {},
|
|
886
1176
|
ttlMs: 4e3
|
|
887
1177
|
};
|
|
888
1178
|
var useReactionsStore = zustand.create()(
|
|
889
1179
|
immer.immer((set) => ({
|
|
890
|
-
...
|
|
1180
|
+
...defaultState3,
|
|
891
1181
|
setReaction: (participantId, reaction) => set((state) => {
|
|
892
1182
|
state.reactions.set(participantId, reaction);
|
|
893
1183
|
}),
|
|
@@ -908,7 +1198,7 @@ var useReactionsStore = zustand.create()(
|
|
|
908
1198
|
clear: () => set(() => ({
|
|
909
1199
|
reactions: /* @__PURE__ */ new Map(),
|
|
910
1200
|
participantCache: {},
|
|
911
|
-
ttlMs:
|
|
1201
|
+
ttlMs: defaultState3.ttlMs
|
|
912
1202
|
}))
|
|
913
1203
|
}))
|
|
914
1204
|
);
|
|
@@ -940,7 +1230,7 @@ function generateNonce() {
|
|
|
940
1230
|
}
|
|
941
1231
|
|
|
942
1232
|
// src/channel/reactions/service.ts
|
|
943
|
-
var
|
|
1233
|
+
var logger5 = createLogger("reactions");
|
|
944
1234
|
var ReactionsService = class {
|
|
945
1235
|
constructor(room) {
|
|
946
1236
|
this.isSubscribed = false;
|
|
@@ -951,15 +1241,15 @@ var ReactionsService = class {
|
|
|
951
1241
|
}
|
|
952
1242
|
isRoomReady() {
|
|
953
1243
|
if (!this.room) {
|
|
954
|
-
|
|
1244
|
+
logger5.warn("Room not initialized");
|
|
955
1245
|
return false;
|
|
956
1246
|
}
|
|
957
1247
|
if (this.room.state !== livekitClient.ConnectionState.Connected) {
|
|
958
|
-
|
|
1248
|
+
logger5.warn("Room not connected", { state: this.room.state });
|
|
959
1249
|
return false;
|
|
960
1250
|
}
|
|
961
1251
|
if (!this.room.localParticipant) {
|
|
962
|
-
|
|
1252
|
+
logger5.warn("Local participant not available");
|
|
963
1253
|
return false;
|
|
964
1254
|
}
|
|
965
1255
|
return true;
|
|
@@ -977,14 +1267,14 @@ var ReactionsService = class {
|
|
|
977
1267
|
const text = await reader.readAll();
|
|
978
1268
|
this.handleIncoming(text);
|
|
979
1269
|
} catch (err) {
|
|
980
|
-
|
|
1270
|
+
logger5.error("Error reading reactions stream", err);
|
|
981
1271
|
}
|
|
982
1272
|
});
|
|
983
1273
|
this.pruneInterval = setInterval(() => {
|
|
984
1274
|
useReactionsStore.getState().pruneExpired();
|
|
985
1275
|
}, 1e3);
|
|
986
1276
|
this.isSubscribed = true;
|
|
987
|
-
|
|
1277
|
+
logger5.info("ReactionsService subscribed");
|
|
988
1278
|
}
|
|
989
1279
|
unsubscribe() {
|
|
990
1280
|
this.isSubscribed = false;
|
|
@@ -992,7 +1282,7 @@ var ReactionsService = class {
|
|
|
992
1282
|
clearInterval(this.pruneInterval);
|
|
993
1283
|
this.pruneInterval = void 0;
|
|
994
1284
|
}
|
|
995
|
-
|
|
1285
|
+
logger5.info("ReactionsService unsubscribed");
|
|
996
1286
|
}
|
|
997
1287
|
getLocalParticipantId() {
|
|
998
1288
|
return this.room.localParticipant.identity;
|
|
@@ -1016,7 +1306,7 @@ var ReactionsService = class {
|
|
|
1016
1306
|
return;
|
|
1017
1307
|
}
|
|
1018
1308
|
if (!this.canSendNow()) {
|
|
1019
|
-
|
|
1309
|
+
logger5.debug("Rate limited, skipping send");
|
|
1020
1310
|
return;
|
|
1021
1311
|
}
|
|
1022
1312
|
const senderInfo = this.getSenderInfo();
|
|
@@ -1042,9 +1332,9 @@ var ReactionsService = class {
|
|
|
1042
1332
|
await this.room.localParticipant.sendText(JSON.stringify(envelope), {
|
|
1043
1333
|
topic: "reactions:v1"
|
|
1044
1334
|
});
|
|
1045
|
-
|
|
1335
|
+
logger5.debug("Reaction sent", { emoji });
|
|
1046
1336
|
} catch (error) {
|
|
1047
|
-
|
|
1337
|
+
logger5.error("Failed to send reaction", error);
|
|
1048
1338
|
useRtcStore.getState().addError({
|
|
1049
1339
|
code: "REACTIONS_SEND_FAILED",
|
|
1050
1340
|
message: error instanceof Error ? error.message : "Failed to send reaction",
|
|
@@ -1057,16 +1347,16 @@ var ReactionsService = class {
|
|
|
1057
1347
|
try {
|
|
1058
1348
|
const parsed = JSON.parse(text);
|
|
1059
1349
|
if (!this.isValidEnvelope(parsed)) {
|
|
1060
|
-
|
|
1350
|
+
logger5.warn("Invalid reaction envelope received", parsed);
|
|
1061
1351
|
return;
|
|
1062
1352
|
}
|
|
1063
1353
|
if (parsed.sender.id === this.getLocalParticipantId()) {
|
|
1064
|
-
|
|
1354
|
+
logger5.debug("Ignoring self-echo reaction");
|
|
1065
1355
|
return;
|
|
1066
1356
|
}
|
|
1067
1357
|
const lastTs = this.lastRemoteTs.get(parsed.sender.id) ?? Number.NEGATIVE_INFINITY;
|
|
1068
1358
|
if (parsed.ts < lastTs) {
|
|
1069
|
-
|
|
1359
|
+
logger5.debug("Ignoring out-of-order reaction", {
|
|
1070
1360
|
sender: parsed.sender.id,
|
|
1071
1361
|
ts: parsed.ts,
|
|
1072
1362
|
lastTs
|
|
@@ -1075,9 +1365,9 @@ var ReactionsService = class {
|
|
|
1075
1365
|
}
|
|
1076
1366
|
this.lastRemoteTs.set(parsed.sender.id, parsed.ts);
|
|
1077
1367
|
applyIncomingReaction(parsed);
|
|
1078
|
-
|
|
1368
|
+
logger5.debug("Reaction received", { emoji: parsed.payload.emoji });
|
|
1079
1369
|
} catch (error) {
|
|
1080
|
-
|
|
1370
|
+
logger5.error("Error parsing incoming reaction", error);
|
|
1081
1371
|
}
|
|
1082
1372
|
}
|
|
1083
1373
|
isValidEnvelope(e) {
|
|
@@ -1099,7 +1389,7 @@ var ReactionsService = class {
|
|
|
1099
1389
|
return sender;
|
|
1100
1390
|
}
|
|
1101
1391
|
};
|
|
1102
|
-
var
|
|
1392
|
+
var logger6 = createLogger("reactions:hook");
|
|
1103
1393
|
function useReactions() {
|
|
1104
1394
|
const service = useFeatureService("reactions");
|
|
1105
1395
|
const reactions = useReactionsStore((state) => state.reactions);
|
|
@@ -1118,7 +1408,7 @@ function useReactions() {
|
|
|
1118
1408
|
const sendReaction = react.useCallback(
|
|
1119
1409
|
async (emoji) => {
|
|
1120
1410
|
if (!service) {
|
|
1121
|
-
|
|
1411
|
+
logger6.error("Cannot send reaction: service not ready");
|
|
1122
1412
|
return;
|
|
1123
1413
|
}
|
|
1124
1414
|
return service.sendReaction(emoji);
|
|
@@ -1148,10 +1438,15 @@ var FEATURES = {
|
|
|
1148
1438
|
name: "reactions",
|
|
1149
1439
|
createService: (room) => new ReactionsService(room),
|
|
1150
1440
|
cleanupStore: () => useReactionsStore.getState().clear()
|
|
1441
|
+
},
|
|
1442
|
+
"raise-hand": {
|
|
1443
|
+
name: "raise-hand",
|
|
1444
|
+
createService: (room) => new RaiseHandService(room),
|
|
1445
|
+
cleanupStore: () => useRaiseHandStore.getState().clear()
|
|
1151
1446
|
}
|
|
1152
1447
|
};
|
|
1153
|
-
var DEFAULT_FEATURES = ["chat", "reactions"];
|
|
1154
|
-
var
|
|
1448
|
+
var DEFAULT_FEATURES = ["chat", "reactions", "raise-hand"];
|
|
1449
|
+
var logger7 = createLogger("channels:provider");
|
|
1155
1450
|
function DataChannelProvider({
|
|
1156
1451
|
room,
|
|
1157
1452
|
features = DEFAULT_FEATURES,
|
|
@@ -1161,52 +1456,52 @@ function DataChannelProvider({
|
|
|
1161
1456
|
const [isReady, setIsReady] = react.useState(false);
|
|
1162
1457
|
react.useEffect(() => {
|
|
1163
1458
|
if (!room) {
|
|
1164
|
-
|
|
1459
|
+
logger7.warn("DataChannelProvider mounted without room");
|
|
1165
1460
|
return;
|
|
1166
1461
|
}
|
|
1167
|
-
|
|
1462
|
+
logger7.debug("Initializing features", { features });
|
|
1168
1463
|
for (const featureName of features) {
|
|
1169
1464
|
const feature = FEATURES[featureName];
|
|
1170
1465
|
if (!feature) {
|
|
1171
|
-
|
|
1466
|
+
logger7.warn(`Feature "${featureName}" not found in registry`);
|
|
1172
1467
|
continue;
|
|
1173
1468
|
}
|
|
1174
1469
|
try {
|
|
1175
|
-
|
|
1470
|
+
logger7.debug(`Initializing feature: ${featureName}`);
|
|
1176
1471
|
const service = feature.createService(room);
|
|
1177
1472
|
service.subscribe();
|
|
1178
1473
|
services.current.set(featureName, service);
|
|
1179
|
-
|
|
1474
|
+
logger7.info(`Feature "${featureName}" initialized`);
|
|
1180
1475
|
} catch (error) {
|
|
1181
|
-
|
|
1476
|
+
logger7.error(`Failed to initialize feature "${featureName}"`, error);
|
|
1182
1477
|
}
|
|
1183
1478
|
}
|
|
1184
1479
|
setIsReady(true);
|
|
1185
|
-
|
|
1480
|
+
logger7.info("All features initialized");
|
|
1186
1481
|
return () => {
|
|
1187
|
-
|
|
1482
|
+
logger7.debug("Cleaning up features");
|
|
1188
1483
|
services.current.forEach((service, name) => {
|
|
1189
1484
|
try {
|
|
1190
|
-
|
|
1485
|
+
logger7.debug(`Unsubscribing feature: ${name}`);
|
|
1191
1486
|
service.unsubscribe();
|
|
1192
1487
|
} catch (error) {
|
|
1193
|
-
|
|
1488
|
+
logger7.error(`Failed to unsubscribe feature "${name}"`, error);
|
|
1194
1489
|
}
|
|
1195
1490
|
});
|
|
1196
1491
|
for (const featureName of features) {
|
|
1197
1492
|
const feature = FEATURES[featureName];
|
|
1198
1493
|
if (feature?.cleanupStore) {
|
|
1199
1494
|
try {
|
|
1200
|
-
|
|
1495
|
+
logger7.debug(`Cleaning store for feature: ${featureName}`);
|
|
1201
1496
|
feature.cleanupStore();
|
|
1202
1497
|
} catch (error) {
|
|
1203
|
-
|
|
1498
|
+
logger7.error(`Failed to cleanup store for "${featureName}"`, error);
|
|
1204
1499
|
}
|
|
1205
1500
|
}
|
|
1206
1501
|
}
|
|
1207
1502
|
services.current.clear();
|
|
1208
1503
|
setIsReady(false);
|
|
1209
|
-
|
|
1504
|
+
logger7.info("Features cleanup complete");
|
|
1210
1505
|
};
|
|
1211
1506
|
}, [room, features]);
|
|
1212
1507
|
const contextValue = react.useMemo(
|
|
@@ -1221,6 +1516,7 @@ function DataChannelProvider({
|
|
|
1221
1516
|
|
|
1222
1517
|
exports.ChatService = ChatService;
|
|
1223
1518
|
exports.DataChannelProvider = DataChannelProvider;
|
|
1519
|
+
exports.RaiseHandService = RaiseHandService;
|
|
1224
1520
|
exports.ReactionsService = ReactionsService;
|
|
1225
1521
|
exports.applyIncomingReaction = applyIncomingReaction;
|
|
1226
1522
|
exports.compareEntries = compareEntries;
|
|
@@ -1232,6 +1528,8 @@ exports.useChat = useChat;
|
|
|
1232
1528
|
exports.useChatStore = useChatStore;
|
|
1233
1529
|
exports.useDataChannelContext = useDataChannelContext;
|
|
1234
1530
|
exports.useFeatureService = useFeatureService;
|
|
1531
|
+
exports.useRaiseHand = useRaiseHand;
|
|
1532
|
+
exports.useRaiseHandStore = useRaiseHandStore;
|
|
1235
1533
|
exports.useReactions = useReactions;
|
|
1236
1534
|
exports.useReactionsStore = useReactionsStore;
|
|
1237
1535
|
exports.validateContent = validateContent;
|