@ai-matrx/meet 0.11.52 → 0.11.54

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
@@ -3617,6 +3617,10 @@ function personOf(identity) {
3617
3617
  const cut = value.indexOf(CONNECTION_SEPARATOR);
3618
3618
  return cut === -1 ? value : value.slice(0, cut);
3619
3619
  }
3620
+ function userIdOfIdentity(identity) {
3621
+ const person = personOf(identity);
3622
+ return person.startsWith("user:") ? person.slice("user:".length) : null;
3623
+ }
3620
3624
  function isGuestIdentity(identity) {
3621
3625
  return personOf(identity).startsWith("guest:");
3622
3626
  }
@@ -3835,6 +3839,7 @@ function consentPending(policy, role, recordingOn, given) {
3835
3839
  function mayAdmitNow(role, participants, policy) {
3836
3840
  if (role === "none") return false;
3837
3841
  if (role === "host" || role === "cohost") return true;
3842
+ if (role === "viewer") return false;
3838
3843
  const hostIn = participants.some((p) => p.role === "host" || p.role === "cohost");
3839
3844
  return !hostIn && policy.headlessPowers === "members_admit";
3840
3845
  }
@@ -4921,21 +4926,35 @@ function heartbeatIntervalMs(roomSize) {
4921
4926
  function staleAfterMs(roomSize) {
4922
4927
  return heartbeatIntervalMs(roomSize) * 3 + 1e3;
4923
4928
  }
4929
+ function firstBeatAllowanceMs(roomSize) {
4930
+ return staleAfterMs(roomSize) * 2;
4931
+ }
4924
4932
  function createLivenessTracker(now) {
4925
4933
  const lastHeard = /* @__PURE__ */ new Map();
4934
+ const firstSeen = /* @__PURE__ */ new Map();
4926
4935
  const beats = /* @__PURE__ */ new Map();
4927
4936
  return {
4928
4937
  heard(who, beat) {
4929
4938
  lastHeard.set(who, now());
4939
+ firstSeen.delete(who);
4930
4940
  if (beat !== null) beats.set(who, beat);
4931
4941
  },
4942
+ expect(who) {
4943
+ if (!lastHeard.has(who) && !firstSeen.has(who)) firstSeen.set(who, now());
4944
+ },
4932
4945
  stale(present, roomSize) {
4933
4946
  const limit = staleAfterMs(roomSize);
4947
+ const firstLimit = firstBeatAllowanceMs(roomSize);
4934
4948
  const at = now();
4935
4949
  const out = /* @__PURE__ */ new Set();
4936
4950
  for (const who of present) {
4937
4951
  const heard = lastHeard.get(who);
4938
- if (heard !== void 0 && at - heard > limit) out.add(who);
4952
+ if (heard !== void 0) {
4953
+ if (at - heard > limit) out.add(who);
4954
+ continue;
4955
+ }
4956
+ const seen = firstSeen.get(who);
4957
+ if (seen !== void 0 && at - seen > firstLimit) out.add(who);
4939
4958
  }
4940
4959
  return out;
4941
4960
  },
@@ -4943,13 +4962,16 @@ function createLivenessTracker(now) {
4943
4962
  restartClock() {
4944
4963
  const at = now();
4945
4964
  for (const who of lastHeard.keys()) lastHeard.set(who, at);
4965
+ for (const who of firstSeen.keys()) firstSeen.set(who, at);
4946
4966
  },
4947
4967
  forget(who) {
4948
4968
  lastHeard.delete(who);
4969
+ firstSeen.delete(who);
4949
4970
  beats.delete(who);
4950
4971
  },
4951
4972
  clear() {
4952
4973
  lastHeard.clear();
4974
+ firstSeen.clear();
4953
4975
  beats.clear();
4954
4976
  }
4955
4977
  };
@@ -5539,6 +5561,17 @@ function createMeetingSession(options) {
5539
5561
  }
5540
5562
  return identity.userId;
5541
5563
  }
5564
+ function requireAdmitterUser(operation) {
5565
+ const snapshot = store.snapshot();
5566
+ if (identity.userId === null || !mayAdmitNow(effectiveRole(snapshot), snapshot.participants, snapshot.livePolicy)) {
5567
+ throw new MeetError(
5568
+ "forbidden",
5569
+ `${operation}: this participant may not let people in`,
5570
+ "Only a host or co-host admits people, unless the meeting has no host in it and lets members admit."
5571
+ );
5572
+ }
5573
+ return identity.userId;
5574
+ }
5542
5575
  function requireMeeting(operation) {
5543
5576
  const meeting = store.snapshot().meeting;
5544
5577
  if (meeting === null) {
@@ -5945,7 +5978,7 @@ function createMeetingSession(options) {
5945
5978
  meetingChannel.requestBackfill("manual");
5946
5979
  },
5947
5980
  async admit(entry, admitted) {
5948
- const by = requireHostUser("meet.admit");
5981
+ const by = requireAdmitterUser("meet.admit");
5949
5982
  const meeting = requireMeeting("meet.admit");
5950
5983
  const row = await repository.decideAdmission({
5951
5984
  meetingId: meeting.id,
@@ -5963,7 +5996,7 @@ function createMeetingSession(options) {
5963
5996
  hint();
5964
5997
  },
5965
5998
  async undeny(entry) {
5966
- const by = requireHostUser("meet.undeny");
5999
+ const by = requireAdmitterUser("meet.undeny");
5967
6000
  const meeting = requireMeeting("meet.undeny");
5968
6001
  const row = await repository.decideAdmission({
5969
6002
  meetingId: meeting.id,
@@ -5976,7 +6009,7 @@ function createMeetingSession(options) {
5976
6009
  hint();
5977
6010
  },
5978
6011
  async admitAll() {
5979
- const by = requireHostUser("meet.admitAll");
6012
+ const by = requireAdmitterUser("meet.admitAll");
5980
6013
  const meeting = requireMeeting("meet.admitAll");
5981
6014
  const rows = await repository.admitAll(meeting.id, by);
5982
6015
  for (const row of rows) {
@@ -7738,6 +7771,13 @@ function createRoomEngine(options) {
7738
7771
  const previous = new Map(liveRoster.map((p) => [p.identity, p]));
7739
7772
  const present = new Set(list.map((p) => p.identity));
7740
7773
  const graceMs = connectionPolicy.reconnectGraceSeconds * 1e3;
7774
+ if (store.snapshot().phase === "in_call") {
7775
+ for (const [who, last] of previous) {
7776
+ if (last.isLocal || present.has(who) || departures.has(who)) continue;
7777
+ departures.set(who, null);
7778
+ report("warn", `meet: ${who} vanished from the room's roster with no departure event; held as reconnecting`, "The media layer dropped a participant silently; the tile is kept for the reconnect grace.");
7779
+ }
7780
+ }
7741
7781
  for (const [who, reason] of departures) {
7742
7782
  const last = previous.get(who);
7743
7783
  const dropped = !saidBye.has(who) && (isUnannouncedDeparture(reason) || silent.has(who));
@@ -7753,6 +7793,9 @@ function createRoomEngine(options) {
7753
7793
  }
7754
7794
  departures.clear();
7755
7795
  liveRoster = list;
7796
+ for (const p of list) {
7797
+ if (!p.isLocal && (isGuestIdentity(p.identity) || userIdOfIdentity(p.identity) !== null)) liveness.expect(p.identity);
7798
+ }
7756
7799
  const localNow = list.find((p) => p.isLocal);
7757
7800
  if (localNow !== void 0 && !localNow.screenSharing && store.snapshot().share.state === "presenting") {
7758
7801
  store.patch({ share: NO_SHARE });
@@ -7773,7 +7816,7 @@ function createRoomEngine(options) {
7773
7816
  store.setParticipants(
7774
7817
  [...people.values()].map(({ entry }) => {
7775
7818
  const projected = projectParticipant(entry, joinedAt);
7776
- if (entry.reconnecting === true || !entry.isLocal && silent.has(entry.identity)) {
7819
+ if (entry.reconnecting === true || !entry.isLocal && silent.has(entry.identity) && !saidBye.has(entry.identity)) {
7777
7820
  return { ...projected, reconnecting: true, quality: "lost" };
7778
7821
  }
7779
7822
  const videoPaused = entry.isLocal ? store.snapshot().localNetwork.videoPaused : liveness.reported(entry.identity)?.vp === true;