@livo-tv/sdk 1.6.1 → 1.7.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.
@@ -5047,10 +5047,11 @@ function StudioRoom({
5047
5047
  ]);
5048
5048
  const verifyGrantTookEffect = react.useCallback(
5049
5049
  (userId, retried = false) => {
5050
+ if (!userId) return;
5050
5051
  const id = window.setTimeout(() => {
5051
- const target = meeting.participants().find((row) => row.userId === userId);
5052
- if (!target || isOnStage(target.stageStatus)) return;
5053
- if (!retried && target.stageStatus === "ACCEPTED_TO_JOIN_STAGE") {
5052
+ const target = meeting.participants().find((row) => row.userId === userId || row.id === userId);
5053
+ if (target && isOnStage(target.stageStatus)) return;
5054
+ if (!retried) {
5054
5055
  void meeting.setStageAccess(userId, true).then(() => {
5055
5056
  verifyGrantTookEffect(userId, true);
5056
5057
  }).catch(() => {
@@ -5064,6 +5065,12 @@ function StudioRoom({
5064
5065
  },
5065
5066
  [labels.stageGrantNoEffect, meeting]
5066
5067
  );
5068
+ react.useEffect(
5069
+ () => meeting.subscribeStageGrant((userId) => {
5070
+ verifyGrantTookEffect(userId);
5071
+ }),
5072
+ [meeting, verifyGrantTookEffect]
5073
+ );
5067
5074
  const onSetStage = react.useCallback(
5068
5075
  async (tile, on) => {
5069
5076
  const userId = tile.userId;
@@ -5388,20 +5395,13 @@ function StudioRoom({
5388
5395
  peopleBadge,
5389
5396
  labels,
5390
5397
  onAdmitAs: (id, as) => {
5391
- const guest = waitlisted.find((row) => row.id === id);
5392
- void Promise.resolve(meeting.admitAs(id, as)).then(() => {
5393
- if (as === "panelist" && guest?.userId) {
5394
- verifyGrantTookEffect(guest.userId);
5395
- }
5398
+ void Promise.resolve(meeting.admitAs(id, as)).catch(() => {
5399
+ sonner.toast.error(labels.stageError);
5396
5400
  });
5397
5401
  },
5398
5402
  onAdmitAll: (as) => {
5399
- const waiting = waitlisted;
5400
- void Promise.resolve(meeting.admitAll(as)).then(() => {
5401
- if (as !== "panelist") return;
5402
- for (const guest of waiting) {
5403
- if (guest.userId) verifyGrantTookEffect(guest.userId);
5404
- }
5403
+ void Promise.resolve(meeting.admitAll(as)).catch(() => {
5404
+ sonner.toast.error(labels.stageError);
5405
5405
  });
5406
5406
  },
5407
5407
  onDeny: (id) => {
@@ -6104,6 +6104,7 @@ function activeSpeakerFrom(payload, fallback) {
6104
6104
  }
6105
6105
  var STAGE_JOIN_RETRY_MS = 1e3;
6106
6106
  var STAGE_JOIN_MAX_ATTEMPTS = 3;
6107
+ var STAGE_GRANT_JOIN_MAX_FAILURES = 8;
6107
6108
  function isStageDisabledError(error) {
6108
6109
  if (!error || typeof error !== "object") return false;
6109
6110
  const row = error;
@@ -6176,12 +6177,15 @@ function studioMeetingFromRtk(raw) {
6176
6177
  const chatListeners = /* @__PURE__ */ new Set();
6177
6178
  const participantListeners = /* @__PURE__ */ new Set();
6178
6179
  const stageListeners = /* @__PURE__ */ new Set();
6180
+ const stageGrantListeners = /* @__PURE__ */ new Set();
6179
6181
  const pinListeners = /* @__PURE__ */ new Set();
6180
6182
  const pendingPanelists = /* @__PURE__ */ new Set();
6181
6183
  const chatSend = /* @__PURE__ */ new Map();
6182
6184
  const nameOverrides = /* @__PURE__ */ new Map();
6183
6185
  let joinStageInFlight = null;
6184
6186
  let joinedStageLocally = false;
6187
+ let stageGrantPending = false;
6188
+ let stageGrantJoinFailures = 0;
6185
6189
  let lastMeetingError = null;
6186
6190
  const historyMessages = [];
6187
6191
  let speakerSinkId = null;
@@ -6280,6 +6284,21 @@ function studioMeetingFromRtk(raw) {
6280
6284
  function currentStageStatus() {
6281
6285
  return meeting.self?.stageStatus ?? meeting.stage?.status;
6282
6286
  }
6287
+ function isStageAccepted() {
6288
+ return meeting.self?.stageStatus === "ACCEPTED_TO_JOIN_STAGE" || meeting.stage?.status === "ACCEPTED_TO_JOIN_STAGE";
6289
+ }
6290
+ function clearStageGrantPending() {
6291
+ stageGrantPending = false;
6292
+ stageGrantJoinFailures = 0;
6293
+ }
6294
+ function notifyStageGrant(userId) {
6295
+ if (!userId) return;
6296
+ for (const listener of stageGrantListeners) listener(userId);
6297
+ }
6298
+ function markStageGranted() {
6299
+ stageGrantPending = true;
6300
+ void ensureStageJoined();
6301
+ }
6283
6302
  function resolveConnectionState() {
6284
6303
  const self = meeting.self;
6285
6304
  const roomState = self?.roomState ?? null;
@@ -6371,22 +6390,21 @@ function studioMeetingFromRtk(raw) {
6371
6390
  joinStageInFlight = null;
6372
6391
  }
6373
6392
  }
6374
- async function autoJoinStage() {
6393
+ async function ensureStageJoined() {
6375
6394
  if (currentStageStatus() === "ON_STAGE") {
6376
- notifyStage();
6395
+ clearStageGrantPending();
6377
6396
  return;
6378
6397
  }
6398
+ if (!stageGrantPending && !isStageAccepted()) return;
6399
+ stageGrantPending = true;
6400
+ if (stageGrantJoinFailures >= STAGE_GRANT_JOIN_MAX_FAILURES) return;
6379
6401
  try {
6380
6402
  await joinStageWithRetry();
6403
+ if (currentStageStatus() === "ON_STAGE") {
6404
+ clearStageGrantPending();
6405
+ }
6381
6406
  } catch {
6382
- notifyStage();
6383
- }
6384
- }
6385
- async function ensureStageJoined() {
6386
- if (currentStageStatus() !== "ACCEPTED_TO_JOIN_STAGE") return;
6387
- try {
6388
- await joinStageWithRetry();
6389
- } catch {
6407
+ stageGrantJoinFailures += 1;
6390
6408
  notifyStage();
6391
6409
  }
6392
6410
  }
@@ -6417,6 +6435,7 @@ function studioMeetingFromRtk(raw) {
6417
6435
  const grantId = takePendingGrantId(joined2);
6418
6436
  if (!grantId) return;
6419
6437
  await meeting.stage?.grantAccess?.([grantId]);
6438
+ notifyStageGrant(joined2?.userId || grantId);
6420
6439
  notifyStage();
6421
6440
  }
6422
6441
  async function grantPendingIfJoined(participantId, userId) {
@@ -6425,6 +6444,7 @@ function studioMeetingFromRtk(raw) {
6425
6444
  if (!grantId) return;
6426
6445
  pendingPanelists.delete(participantId);
6427
6446
  await meeting.stage?.grantAccess?.([grantId]);
6447
+ notifyStageGrant(already?.userId || grantId);
6428
6448
  notifyStage();
6429
6449
  }
6430
6450
  listen(meeting.self, "videoUpdate", rebindMedia);
@@ -6474,15 +6494,15 @@ function studioMeetingFromRtk(raw) {
6474
6494
  listen(meeting.stage, "stageAccessRequestUpdate", notifyStage);
6475
6495
  listen(meeting.stage, "newStageRequest", notifyStage);
6476
6496
  listen(meeting.stage, "stageRequestApproved", () => {
6477
- void autoJoinStage();
6497
+ markStageGranted();
6498
+ });
6499
+ listen(meeting.stage, "acceptPresentRequests", () => {
6500
+ markStageGranted();
6478
6501
  });
6479
6502
  listen(meeting.stage, "stageRequestRejected", notifyStage);
6480
- listen(meeting.stage, "stageStatusUpdate", (status) => {
6481
- if (status === "ACCEPTED_TO_JOIN_STAGE") {
6482
- void autoJoinStage();
6483
- return;
6484
- }
6485
- if (status === "ON_STAGE") {
6503
+ listen(meeting.stage, "stageStatusUpdate", () => {
6504
+ if (currentStageStatus() === "ON_STAGE") {
6505
+ clearStageGrantPending();
6486
6506
  if (joinedStageLocally) {
6487
6507
  joinedStageLocally = false;
6488
6508
  notifyStage();
@@ -6493,12 +6513,17 @@ function studioMeetingFromRtk(raw) {
6493
6513
  });
6494
6514
  return;
6495
6515
  }
6516
+ if (isStageAccepted()) {
6517
+ markStageGranted();
6518
+ return;
6519
+ }
6496
6520
  notifyStage();
6497
6521
  });
6498
6522
  return {
6499
6523
  async join() {
6500
6524
  await meeting.join?.();
6501
6525
  await joinStageIfAllowed();
6526
+ await ensureStageJoined();
6502
6527
  await applyCurrentVideoEffects();
6503
6528
  },
6504
6529
  async leave() {
@@ -6594,7 +6619,12 @@ function studioMeetingFromRtk(raw) {
6594
6619
  return;
6595
6620
  }
6596
6621
  if (on) await meeting.stage?.grantAccess?.([userId]);
6597
- else await meeting.stage?.kick?.([userId]);
6622
+ else {
6623
+ await meeting.stage?.kick?.([userId]);
6624
+ if (meeting.self?.userId === userId) {
6625
+ clearStageGrantPending();
6626
+ }
6627
+ }
6598
6628
  notifyStage();
6599
6629
  },
6600
6630
  async denyStageAccess(userId) {
@@ -6625,6 +6655,7 @@ function studioMeetingFromRtk(raw) {
6625
6655
  async leaveStage() {
6626
6656
  await meeting.stage?.leave?.();
6627
6657
  joinedStageLocally = false;
6658
+ clearStageGrantPending();
6628
6659
  notifyStage();
6629
6660
  },
6630
6661
  stageStatus() {
@@ -6656,6 +6687,12 @@ function studioMeetingFromRtk(raw) {
6656
6687
  stageListeners.delete(cb);
6657
6688
  };
6658
6689
  },
6690
+ subscribeStageGrant(cb) {
6691
+ stageGrantListeners.add(cb);
6692
+ return () => {
6693
+ stageGrantListeners.delete(cb);
6694
+ };
6695
+ },
6659
6696
  canManageStage() {
6660
6697
  return meeting.self?.permissions?.acceptStageRequests === true;
6661
6698
  },