@ai-matrx/meet 0.11.51 → 0.11.53

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.js CHANGED
@@ -3551,6 +3551,7 @@ function consentPending(policy, role, recordingOn, given) {
3551
3551
  function mayAdmitNow(role, participants, policy) {
3552
3552
  if (role === "none") return false;
3553
3553
  if (role === "host" || role === "cohost") return true;
3554
+ if (role === "viewer") return false;
3554
3555
  const hostIn = participants.some((p) => p.role === "host" || p.role === "cohost");
3555
3556
  return !hostIn && policy.headlessPowers === "members_admit";
3556
3557
  }
@@ -4612,6 +4613,16 @@ var ALIVE_TOPIC = "mx.alive";
4612
4613
  function encodeBeat(beat) {
4613
4614
  return JSON.stringify({ q: beat.q, vp: beat.vp });
4614
4615
  }
4616
+ function encodeBye() {
4617
+ return JSON.stringify({ bye: true });
4618
+ }
4619
+ function isBye(payload) {
4620
+ try {
4621
+ return JSON.parse(payload).bye === true;
4622
+ } catch {
4623
+ return false;
4624
+ }
4625
+ }
4615
4626
  function decodeBeat(payload) {
4616
4627
  try {
4617
4628
  const raw = JSON.parse(payload);
@@ -5245,6 +5256,17 @@ function createMeetingSession(options) {
5245
5256
  }
5246
5257
  return identity.userId;
5247
5258
  }
5259
+ function requireAdmitterUser(operation) {
5260
+ const snapshot = store.snapshot();
5261
+ if (identity.userId === null || !mayAdmitNow(effectiveRole(snapshot), snapshot.participants, snapshot.livePolicy)) {
5262
+ throw new MeetError(
5263
+ "forbidden",
5264
+ `${operation}: this participant may not let people in`,
5265
+ "Only a host or co-host admits people, unless the meeting has no host in it and lets members admit."
5266
+ );
5267
+ }
5268
+ return identity.userId;
5269
+ }
5248
5270
  function requireMeeting(operation) {
5249
5271
  const meeting = store.snapshot().meeting;
5250
5272
  if (meeting === null) {
@@ -5651,7 +5673,7 @@ function createMeetingSession(options) {
5651
5673
  meetingChannel.requestBackfill("manual");
5652
5674
  },
5653
5675
  async admit(entry, admitted) {
5654
- const by = requireHostUser("meet.admit");
5676
+ const by = requireAdmitterUser("meet.admit");
5655
5677
  const meeting = requireMeeting("meet.admit");
5656
5678
  const row = await repository.decideAdmission({
5657
5679
  meetingId: meeting.id,
@@ -5669,7 +5691,7 @@ function createMeetingSession(options) {
5669
5691
  hint();
5670
5692
  },
5671
5693
  async undeny(entry) {
5672
- const by = requireHostUser("meet.undeny");
5694
+ const by = requireAdmitterUser("meet.undeny");
5673
5695
  const meeting = requireMeeting("meet.undeny");
5674
5696
  const row = await repository.decideAdmission({
5675
5697
  meetingId: meeting.id,
@@ -5682,7 +5704,7 @@ function createMeetingSession(options) {
5682
5704
  hint();
5683
5705
  },
5684
5706
  async admitAll() {
5685
- const by = requireHostUser("meet.admitAll");
5707
+ const by = requireAdmitterUser("meet.admitAll");
5686
5708
  const meeting = requireMeeting("meet.admitAll");
5687
5709
  const rows = await repository.admitAll(meeting.id, by);
5688
5710
  for (const row of rows) {
@@ -6861,6 +6883,7 @@ function createRoomEngine(options) {
6861
6883
  const autoOff = createVideoAutoOff(() => connectionPolicy.videoAutoOffAfterPoorSeconds * 1e3, now);
6862
6884
  const lkQuality = /* @__PURE__ */ new Map();
6863
6885
  let silent = /* @__PURE__ */ new Set();
6886
+ const saidBye = /* @__PURE__ */ new Set();
6864
6887
  let healthTimer = null;
6865
6888
  let lastBeatAt = 0;
6866
6889
  let wasUnstable = false;
@@ -6891,6 +6914,7 @@ function createRoomEngine(options) {
6891
6914
  assessor.reset();
6892
6915
  autoOff.reset();
6893
6916
  silent = /* @__PURE__ */ new Set();
6917
+ saidBye.clear();
6894
6918
  lkQuality.clear();
6895
6919
  lastBeatAt = 0;
6896
6920
  wasUnstable = false;
@@ -6948,6 +6972,13 @@ function createRoomEngine(options) {
6948
6972
  await target?.disconnect();
6949
6973
  }
6950
6974
  async function leaveRoom() {
6975
+ const target = driver;
6976
+ if (target !== null && store.snapshot().phase === "in_call") {
6977
+ await Promise.race([
6978
+ target.publishData(ALIVE_TOPIC, encodeBye()).catch(() => void 0),
6979
+ new Promise((resolve) => setTimeout(resolve, 300))
6980
+ ]);
6981
+ }
6951
6982
  store.dispatch({ type: "leave" });
6952
6983
  await dropRoom();
6953
6984
  options.onLeft?.(null);
@@ -7043,8 +7074,6 @@ function createRoomEngine(options) {
7043
7074
  },
7044
7075
  participantLeft(who, reason) {
7045
7076
  departures.set(who, reason);
7046
- liveness.forget(who);
7047
- silent.delete(who);
7048
7077
  },
7049
7078
  roomMetadata(metadata) {
7050
7079
  let parsed = {};
@@ -7087,8 +7116,12 @@ function createRoomEngine(options) {
7087
7116
  const snap = store.snapshot();
7088
7117
  if (snap.phase !== "in_call" || snap.connection !== "stable") return;
7089
7118
  startHealth();
7119
+ const before = assessor.current();
7090
7120
  const quality = assessor.push(reading);
7091
7121
  const path = pathOf(reading);
7122
+ if (quality !== before) {
7123
+ report("info", `meet: this connection reads ${quality} (round trip ${reading.rttMs ?? "?"} ms, path ${path})`, "Diagnostic only.");
7124
+ }
7092
7125
  patchLocalNetwork({ quality, ...path !== "unknown" ? { path } : {} });
7093
7126
  refreshQualities();
7094
7127
  const cameraOn = snap.media.camera.enabled;
@@ -7103,6 +7136,11 @@ function createRoomEngine(options) {
7103
7136
  connectionState(state) {
7104
7137
  supervisor.driverState(state);
7105
7138
  if (state === "connected" && store.snapshot().phase === "joining") store.dispatch({ type: "connected" });
7139
+ if (state === "connected") {
7140
+ startHealth();
7141
+ lastBeatAt = 0;
7142
+ healthTick();
7143
+ }
7106
7144
  },
7107
7145
  transcription(event) {
7108
7146
  const snapshot = store.snapshot();
@@ -7194,6 +7232,10 @@ function createRoomEngine(options) {
7194
7232
  }
7195
7233
  const sender = personOf(from ?? "");
7196
7234
  if (from !== null) {
7235
+ if (topic === ALIVE_TOPIC && isBye(payload)) {
7236
+ saidBye.add(from);
7237
+ return;
7238
+ }
7197
7239
  const beat = topic === ALIVE_TOPIC ? decodeBeat(payload) : null;
7198
7240
  const before = liveness.reported(from);
7199
7241
  liveness.heard(from, beat);
@@ -7426,10 +7468,17 @@ function createRoomEngine(options) {
7426
7468
  const graceMs = connectionPolicy.reconnectGraceSeconds * 1e3;
7427
7469
  for (const [who, reason] of departures) {
7428
7470
  const last = previous.get(who);
7429
- if (last !== void 0 && !last.isLocal && !present.has(who) && graceMs > 0 && isUnannouncedDeparture(reason)) {
7471
+ const dropped = !saidBye.has(who) && (isUnannouncedDeparture(reason) || silent.has(who));
7472
+ report("info", `meet: ${who} left the room (${reason ?? "no reason"}${dropped ? ", held as reconnecting" : ""})`, "Diagnostic only.");
7473
+ if (last !== void 0 && !last.isLocal && !present.has(who) && graceMs > 0 && dropped) {
7430
7474
  ghosts.set(who, { participant: last, until: at + graceMs });
7431
7475
  }
7432
7476
  }
7477
+ for (const who of departures.keys()) {
7478
+ liveness.forget(who);
7479
+ silent.delete(who);
7480
+ saidBye.delete(who);
7481
+ }
7433
7482
  departures.clear();
7434
7483
  liveRoster = list;
7435
7484
  const localNow = list.find((p) => p.isLocal);