vg-x07df 1.9.5 → 1.10.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.cjs CHANGED
@@ -1913,6 +1913,14 @@ var callParticipantAddedSchema = zod.z.object({
1913
1913
  var callParticipantKickedSchema = zod.z.object({
1914
1914
  callId: zod.z.string(),
1915
1915
  participantId: zod.z.string(),
1916
+ userId: zod.z.string(),
1917
+ reason: zod.z.string().optional()
1918
+ }).strict();
1919
+ var callParticipantLeftSchema = zod.z.object({
1920
+ callId: zod.z.string(),
1921
+ userId: zod.z.string(),
1922
+ participantId: zod.z.string(),
1923
+ leftAt: zod.z.string(),
1916
1924
  reason: zod.z.string().optional()
1917
1925
  }).strict();
1918
1926
  var callReadySchema = zod.z.object({
@@ -2272,8 +2280,14 @@ var CallParticipantKickedHandler = class extends BaseSocketHandler {
2272
2280
  participantId: data.participantId,
2273
2281
  reason: data.reason
2274
2282
  });
2283
+ this.updateStore((state) => {
2284
+ if (data.userId && state.outgoingInvites[data.userId]) {
2285
+ delete state.outgoingInvites[data.userId];
2286
+ }
2287
+ });
2275
2288
  this.logger.debug("Participant kicked from call", {
2276
- participantId: data.participantId
2289
+ participantId: data.participantId,
2290
+ userId: data.userId
2277
2291
  });
2278
2292
  }
2279
2293
  };
@@ -2480,6 +2494,12 @@ var InviteMissedHandler = class extends BaseSocketHandler {
2480
2494
  userId: data.userId
2481
2495
  });
2482
2496
  if (currentState.session?.id !== data.callId) {
2497
+ this.logger.warn("Invite missed ignored due to session mismatch", {
2498
+ eventCallId: data.callId,
2499
+ sessionCallId: currentState.session?.id,
2500
+ hasSession: !!currentState.session,
2501
+ outgoingInviteKeys: Object.keys(currentState.outgoingInvites || {})
2502
+ });
2483
2503
  pushStaleEventError("call:inviteMissed", "callId mismatch", {
2484
2504
  eventCallId: data.callId,
2485
2505
  sessionCallId: currentState.session?.id
@@ -2615,6 +2635,42 @@ var ParticipantAddedHandler = class extends BaseSocketHandler {
2615
2635
  }
2616
2636
  };
2617
2637
 
2638
+ // src/core/socketio/handlers/participant-left.handler.ts
2639
+ var ParticipantLeftHandler = class extends BaseSocketHandler {
2640
+ constructor() {
2641
+ super(...arguments);
2642
+ this.eventName = "call:participantLeft";
2643
+ this.schema = callParticipantLeftSchema;
2644
+ }
2645
+ handle(data) {
2646
+ const currentState = rtcStore.getState();
2647
+ this.logger.info("Participant left call", {
2648
+ callId: data.callId,
2649
+ userId: data.userId,
2650
+ participantId: data.participantId
2651
+ });
2652
+ if (currentState.session?.id !== data.callId) {
2653
+ pushStaleEventError("call:participantLeft", "callId mismatch", {
2654
+ eventCallId: data.callId,
2655
+ sessionCallId: currentState.session?.id
2656
+ });
2657
+ this.logger.warn("Ignoring participant left for different call", {
2658
+ callId: data.callId
2659
+ });
2660
+ return;
2661
+ }
2662
+ this.updateStore((state) => {
2663
+ if (state.outgoingInvites[data.userId]) {
2664
+ state.outgoingInvites[data.userId].status = "left";
2665
+ this.logger.info("Outgoing invite marked as left", {
2666
+ userId: data.userId,
2667
+ callId: data.callId
2668
+ });
2669
+ }
2670
+ });
2671
+ }
2672
+ };
2673
+
2618
2674
  // src/core/socketio/handlers/participant-profiles.handler.ts
2619
2675
  var ParticipantProfilesHandler = class extends BaseSocketHandler {
2620
2676
  constructor() {
@@ -2792,6 +2848,7 @@ var SocketHandlerRegistry = class {
2792
2848
  new InviteCancelledHandler(this.options),
2793
2849
  // Participant management
2794
2850
  new ParticipantAddedHandler(this.options),
2851
+ new ParticipantLeftHandler(this.options),
2795
2852
  new CallParticipantKickedHandler(this.options),
2796
2853
  // Profile hydration
2797
2854
  new ParticipantProfilesHandler(this.options),
@@ -3976,7 +4033,8 @@ function createPresenceService(config, deps) {
3976
4033
  if (userIds.length === 0) {
3977
4034
  return [];
3978
4035
  }
3979
- const cacheKey = [...userIds].sort().join(",");
4036
+ const uniqueUserIds = Array.from(new Set(userIds));
4037
+ const cacheKey = [...uniqueUserIds].sort().join(",");
3980
4038
  const existing = inFlight.get(cacheKey);
3981
4039
  if (existing) {
3982
4040
  logger7.debug("Reusing in-flight request", { cacheKey });
@@ -3984,7 +4042,7 @@ function createPresenceService(config, deps) {
3984
4042
  }
3985
4043
  const fetchPromise = (async () => {
3986
4044
  try {
3987
- const response = await signalPresence.queryPresence(userIds);
4045
+ const response = await signalPresence.queryPresence(uniqueUserIds);
3988
4046
  return response.presence.map((p) => ({
3989
4047
  userId: p.userId,
3990
4048
  status: p.status,
@@ -5011,56 +5069,105 @@ var useScreenShare = () => {
5011
5069
  handleStopScreenShare
5012
5070
  };
5013
5071
  };
5014
- function usePresence(userId) {
5072
+ function usePresence(userId, options) {
5015
5073
  const sdk = useSdk();
5016
5074
  const [presence, setPresence] = React.useState();
5017
5075
  const [isLoading, setIsLoading] = React.useState(false);
5076
+ const [error, setError] = React.useState(null);
5077
+ const isMountedRef = React.useRef(true);
5018
5078
  const refetch = React.useCallback(async () => {
5019
5079
  if (!userId) return;
5020
5080
  setIsLoading(true);
5081
+ setError(null);
5021
5082
  try {
5022
5083
  const result = await sdk.presence.getPresence(userId);
5023
- setPresence(result);
5084
+ if (isMountedRef.current) {
5085
+ setPresence(result);
5086
+ }
5087
+ } catch (err) {
5088
+ if (isMountedRef.current) {
5089
+ setError(err);
5090
+ }
5024
5091
  } finally {
5025
- setIsLoading(false);
5092
+ if (isMountedRef.current) {
5093
+ setIsLoading(false);
5094
+ }
5026
5095
  }
5027
5096
  }, [sdk, userId]);
5028
5097
  React.useEffect(() => {
5029
5098
  refetch();
5030
5099
  }, [refetch]);
5100
+ React.useEffect(() => {
5101
+ if (!options?.pollIntervalMs) return;
5102
+ const id = setInterval(refetch, options.pollIntervalMs);
5103
+ return () => clearInterval(id);
5104
+ }, [options?.pollIntervalMs, refetch]);
5105
+ React.useEffect(() => {
5106
+ return () => {
5107
+ isMountedRef.current = false;
5108
+ };
5109
+ }, []);
5031
5110
  return {
5032
5111
  presence,
5033
5112
  status: presence?.status,
5113
+ resolvedStatus: error ? "unknown" : presence?.status,
5034
5114
  isLoading,
5115
+ error,
5035
5116
  refetch
5036
5117
  };
5037
5118
  }
5038
- function usePresenceMany(userIds) {
5119
+ function usePresenceMany(userIds, options) {
5039
5120
  const sdk = useSdk();
5040
5121
  const [presences, setPresences] = React.useState(
5041
5122
  /* @__PURE__ */ new Map()
5042
5123
  );
5043
5124
  const [isLoading, setIsLoading] = React.useState(false);
5125
+ const [error, setError] = React.useState(null);
5126
+ const isMountedRef = React.useRef(true);
5044
5127
  const refetch = React.useCallback(async () => {
5045
5128
  if (userIds.length === 0) return;
5046
5129
  setIsLoading(true);
5130
+ setError(null);
5047
5131
  try {
5048
5132
  const results = await sdk.presence.queryPresence(userIds);
5049
5133
  const map = /* @__PURE__ */ new Map();
5050
5134
  for (const p of results) {
5051
5135
  map.set(p.userId, p);
5052
5136
  }
5053
- setPresences(map);
5137
+ if (isMountedRef.current) {
5138
+ setPresences(map);
5139
+ }
5140
+ } catch (err) {
5141
+ if (isMountedRef.current) {
5142
+ setError(err);
5143
+ }
5054
5144
  } finally {
5055
- setIsLoading(false);
5145
+ if (isMountedRef.current) {
5146
+ setIsLoading(false);
5147
+ }
5056
5148
  }
5057
5149
  }, [sdk, userIds]);
5058
5150
  React.useEffect(() => {
5059
5151
  refetch();
5060
5152
  }, [refetch]);
5153
+ React.useEffect(() => {
5154
+ if (!options?.pollIntervalMs) return;
5155
+ const id = setInterval(refetch, options.pollIntervalMs);
5156
+ return () => clearInterval(id);
5157
+ }, [options?.pollIntervalMs, refetch]);
5158
+ React.useEffect(() => {
5159
+ return () => {
5160
+ isMountedRef.current = false;
5161
+ };
5162
+ }, []);
5061
5163
  return {
5062
5164
  presences,
5063
5165
  isLoading,
5166
+ error,
5167
+ getStatus: (userId) => {
5168
+ if (error) return "unknown";
5169
+ return presences.get(userId)?.status;
5170
+ },
5064
5171
  refetch
5065
5172
  };
5066
5173
  }
@@ -5172,6 +5279,7 @@ exports.callInviteMissedSchema = callInviteMissedSchema;
5172
5279
  exports.callInviteSchema = callInviteSchema;
5173
5280
  exports.callParticipantAddedSchema = callParticipantAddedSchema;
5174
5281
  exports.callParticipantKickedSchema = callParticipantKickedSchema;
5282
+ exports.callParticipantLeftSchema = callParticipantLeftSchema;
5175
5283
  exports.callReadySchema = callReadySchema;
5176
5284
  exports.callRecordingStartedSchema = callRecordingStartedSchema;
5177
5285
  exports.callRecordingStoppedSchema = callRecordingStoppedSchema;