@ai-matrx/meet 0.11.50 → 0.11.52

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
@@ -216,7 +216,8 @@ var DEFAULT_CONNECTION_POLICY = {
216
216
  autoRejoin: true,
217
217
  autoRejoinMaxAttempts: 5,
218
218
  reconnectGraceSeconds: 30,
219
- videoAutoOffAfterPoorSeconds: 20
219
+ videoAutoOffAfterPoorSeconds: 20,
220
+ captionsStartTimeoutSeconds: 20
220
221
  };
221
222
  function clampInt(value, min, max, fallback) {
222
223
  if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
@@ -231,7 +232,8 @@ function connectionPolicyFrom(raw) {
231
232
  autoRejoin: typeof row["auto_rejoin"] === "boolean" ? row["auto_rejoin"] : d.autoRejoin,
232
233
  autoRejoinMaxAttempts: clampInt(row["auto_rejoin_max_attempts"], 0, 20, d.autoRejoinMaxAttempts),
233
234
  reconnectGraceSeconds: clampInt(row["reconnect_grace_seconds"], 0, 600, d.reconnectGraceSeconds),
234
- videoAutoOffAfterPoorSeconds: clampInt(row["video_auto_off_after_poor_seconds"], 0, 600, d.videoAutoOffAfterPoorSeconds)
235
+ videoAutoOffAfterPoorSeconds: clampInt(row["video_auto_off_after_poor_seconds"], 0, 600, d.videoAutoOffAfterPoorSeconds),
236
+ captionsStartTimeoutSeconds: clampInt(row["captions_start_timeout_seconds"], 1, 600, d.captionsStartTimeoutSeconds)
235
237
  };
236
238
  }
237
239
  var LIVEKIT_BASE_DELAYS_MS = [0, 300, 1200, 2700, 4800, 7e3];
@@ -3643,6 +3645,7 @@ var EMPTY = {
3643
3645
  noteTakerRefusal: null,
3644
3646
  captionsOn: false,
3645
3647
  captionsRefusal: null,
3648
+ captionsStartTimeoutSeconds: 20,
3646
3649
  media: IDLE_MEDIA,
3647
3650
  mediaRegion: IDLE_MEDIA_REGION,
3648
3651
  failure: null,
@@ -4609,6 +4612,16 @@ var ALIVE_TOPIC = "mx.alive";
4609
4612
  function encodeBeat(beat) {
4610
4613
  return JSON.stringify({ q: beat.q, vp: beat.vp });
4611
4614
  }
4615
+ function encodeBye() {
4616
+ return JSON.stringify({ bye: true });
4617
+ }
4618
+ function isBye(payload) {
4619
+ try {
4620
+ return JSON.parse(payload).bye === true;
4621
+ } catch {
4622
+ return false;
4623
+ }
4624
+ }
4612
4625
  function decodeBeat(payload) {
4613
4626
  try {
4614
4627
  const raw = JSON.parse(payload);
@@ -6858,6 +6871,7 @@ function createRoomEngine(options) {
6858
6871
  const autoOff = createVideoAutoOff(() => connectionPolicy.videoAutoOffAfterPoorSeconds * 1e3, now);
6859
6872
  const lkQuality = /* @__PURE__ */ new Map();
6860
6873
  let silent = /* @__PURE__ */ new Set();
6874
+ const saidBye = /* @__PURE__ */ new Set();
6861
6875
  let healthTimer = null;
6862
6876
  let lastBeatAt = 0;
6863
6877
  let wasUnstable = false;
@@ -6888,6 +6902,7 @@ function createRoomEngine(options) {
6888
6902
  assessor.reset();
6889
6903
  autoOff.reset();
6890
6904
  silent = /* @__PURE__ */ new Set();
6905
+ saidBye.clear();
6891
6906
  lkQuality.clear();
6892
6907
  lastBeatAt = 0;
6893
6908
  wasUnstable = false;
@@ -6945,6 +6960,13 @@ function createRoomEngine(options) {
6945
6960
  await target?.disconnect();
6946
6961
  }
6947
6962
  async function leaveRoom() {
6963
+ const target = driver;
6964
+ if (target !== null && store.snapshot().phase === "in_call") {
6965
+ await Promise.race([
6966
+ target.publishData(ALIVE_TOPIC, encodeBye()).catch(() => void 0),
6967
+ new Promise((resolve) => setTimeout(resolve, 300))
6968
+ ]);
6969
+ }
6948
6970
  store.dispatch({ type: "leave" });
6949
6971
  await dropRoom();
6950
6972
  options.onLeft?.(null);
@@ -7040,8 +7062,6 @@ function createRoomEngine(options) {
7040
7062
  },
7041
7063
  participantLeft(who, reason) {
7042
7064
  departures.set(who, reason);
7043
- liveness.forget(who);
7044
- silent.delete(who);
7045
7065
  },
7046
7066
  roomMetadata(metadata) {
7047
7067
  let parsed = {};
@@ -7084,8 +7104,12 @@ function createRoomEngine(options) {
7084
7104
  const snap = store.snapshot();
7085
7105
  if (snap.phase !== "in_call" || snap.connection !== "stable") return;
7086
7106
  startHealth();
7107
+ const before = assessor.current();
7087
7108
  const quality = assessor.push(reading);
7088
7109
  const path = pathOf(reading);
7110
+ if (quality !== before) {
7111
+ report("info", `meet: this connection reads ${quality} (round trip ${reading.rttMs ?? "?"} ms, path ${path})`, "Diagnostic only.");
7112
+ }
7089
7113
  patchLocalNetwork({ quality, ...path !== "unknown" ? { path } : {} });
7090
7114
  refreshQualities();
7091
7115
  const cameraOn = snap.media.camera.enabled;
@@ -7100,6 +7124,11 @@ function createRoomEngine(options) {
7100
7124
  connectionState(state) {
7101
7125
  supervisor.driverState(state);
7102
7126
  if (state === "connected" && store.snapshot().phase === "joining") store.dispatch({ type: "connected" });
7127
+ if (state === "connected") {
7128
+ startHealth();
7129
+ lastBeatAt = 0;
7130
+ healthTick();
7131
+ }
7103
7132
  },
7104
7133
  transcription(event) {
7105
7134
  const snapshot = store.snapshot();
@@ -7191,6 +7220,10 @@ function createRoomEngine(options) {
7191
7220
  }
7192
7221
  const sender = personOf(from ?? "");
7193
7222
  if (from !== null) {
7223
+ if (topic === ALIVE_TOPIC && isBye(payload)) {
7224
+ saidBye.add(from);
7225
+ return;
7226
+ }
7194
7227
  const beat = topic === ALIVE_TOPIC ? decodeBeat(payload) : null;
7195
7228
  const before = liveness.reported(from);
7196
7229
  liveness.heard(from, beat);
@@ -7305,6 +7338,7 @@ function createRoomEngine(options) {
7305
7338
  current = token;
7306
7339
  lastServerUrl = token.serverUrl;
7307
7340
  connectionPolicy = token.connectionPolicy ?? DEFAULT_CONNECTION_POLICY;
7341
+ store.patch({ captionsStartTimeoutSeconds: connectionPolicy.captionsStartTimeoutSeconds });
7308
7342
  if (token.leavePolicy !== void 0) store.patch({ leavePolicy: token.leavePolicy });
7309
7343
  store.patch({ canReclaim: token.canReclaim === true });
7310
7344
  store.patch({
@@ -7422,10 +7456,17 @@ function createRoomEngine(options) {
7422
7456
  const graceMs = connectionPolicy.reconnectGraceSeconds * 1e3;
7423
7457
  for (const [who, reason] of departures) {
7424
7458
  const last = previous.get(who);
7425
- if (last !== void 0 && !last.isLocal && !present.has(who) && graceMs > 0 && isUnannouncedDeparture(reason)) {
7459
+ const dropped = !saidBye.has(who) && (isUnannouncedDeparture(reason) || silent.has(who));
7460
+ report("info", `meet: ${who} left the room (${reason ?? "no reason"}${dropped ? ", held as reconnecting" : ""})`, "Diagnostic only.");
7461
+ if (last !== void 0 && !last.isLocal && !present.has(who) && graceMs > 0 && dropped) {
7426
7462
  ghosts.set(who, { participant: last, until: at + graceMs });
7427
7463
  }
7428
7464
  }
7465
+ for (const who of departures.keys()) {
7466
+ liveness.forget(who);
7467
+ silent.delete(who);
7468
+ saidBye.delete(who);
7469
+ }
7429
7470
  departures.clear();
7430
7471
  liveRoster = list;
7431
7472
  const localNow = list.find((p) => p.isLocal);