@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.cjs CHANGED
@@ -500,7 +500,8 @@ var DEFAULT_CONNECTION_POLICY = {
500
500
  autoRejoin: true,
501
501
  autoRejoinMaxAttempts: 5,
502
502
  reconnectGraceSeconds: 30,
503
- videoAutoOffAfterPoorSeconds: 20
503
+ videoAutoOffAfterPoorSeconds: 20,
504
+ captionsStartTimeoutSeconds: 20
504
505
  };
505
506
  function clampInt(value, min, max, fallback) {
506
507
  if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
@@ -515,7 +516,8 @@ function connectionPolicyFrom(raw) {
515
516
  autoRejoin: typeof row["auto_rejoin"] === "boolean" ? row["auto_rejoin"] : d.autoRejoin,
516
517
  autoRejoinMaxAttempts: clampInt(row["auto_rejoin_max_attempts"], 0, 20, d.autoRejoinMaxAttempts),
517
518
  reconnectGraceSeconds: clampInt(row["reconnect_grace_seconds"], 0, 600, d.reconnectGraceSeconds),
518
- videoAutoOffAfterPoorSeconds: clampInt(row["video_auto_off_after_poor_seconds"], 0, 600, d.videoAutoOffAfterPoorSeconds)
519
+ videoAutoOffAfterPoorSeconds: clampInt(row["video_auto_off_after_poor_seconds"], 0, 600, d.videoAutoOffAfterPoorSeconds),
520
+ captionsStartTimeoutSeconds: clampInt(row["captions_start_timeout_seconds"], 1, 600, d.captionsStartTimeoutSeconds)
519
521
  };
520
522
  }
521
523
  var LIVEKIT_BASE_DELAYS_MS = [0, 300, 1200, 2700, 4800, 7e3];
@@ -3927,6 +3929,7 @@ var EMPTY = {
3927
3929
  noteTakerRefusal: null,
3928
3930
  captionsOn: false,
3929
3931
  captionsRefusal: null,
3932
+ captionsStartTimeoutSeconds: 20,
3930
3933
  media: IDLE_MEDIA,
3931
3934
  mediaRegion: IDLE_MEDIA_REGION,
3932
3935
  failure: null,
@@ -4893,6 +4896,16 @@ var ALIVE_TOPIC = "mx.alive";
4893
4896
  function encodeBeat(beat) {
4894
4897
  return JSON.stringify({ q: beat.q, vp: beat.vp });
4895
4898
  }
4899
+ function encodeBye() {
4900
+ return JSON.stringify({ bye: true });
4901
+ }
4902
+ function isBye(payload) {
4903
+ try {
4904
+ return JSON.parse(payload).bye === true;
4905
+ } catch {
4906
+ return false;
4907
+ }
4908
+ }
4896
4909
  function decodeBeat(payload) {
4897
4910
  try {
4898
4911
  const raw = JSON.parse(payload);
@@ -7142,6 +7155,7 @@ function createRoomEngine(options) {
7142
7155
  const autoOff = createVideoAutoOff(() => connectionPolicy.videoAutoOffAfterPoorSeconds * 1e3, now);
7143
7156
  const lkQuality = /* @__PURE__ */ new Map();
7144
7157
  let silent = /* @__PURE__ */ new Set();
7158
+ const saidBye = /* @__PURE__ */ new Set();
7145
7159
  let healthTimer = null;
7146
7160
  let lastBeatAt = 0;
7147
7161
  let wasUnstable = false;
@@ -7172,6 +7186,7 @@ function createRoomEngine(options) {
7172
7186
  assessor.reset();
7173
7187
  autoOff.reset();
7174
7188
  silent = /* @__PURE__ */ new Set();
7189
+ saidBye.clear();
7175
7190
  lkQuality.clear();
7176
7191
  lastBeatAt = 0;
7177
7192
  wasUnstable = false;
@@ -7229,6 +7244,13 @@ function createRoomEngine(options) {
7229
7244
  await target?.disconnect();
7230
7245
  }
7231
7246
  async function leaveRoom() {
7247
+ const target = driver;
7248
+ if (target !== null && store.snapshot().phase === "in_call") {
7249
+ await Promise.race([
7250
+ target.publishData(ALIVE_TOPIC, encodeBye()).catch(() => void 0),
7251
+ new Promise((resolve) => setTimeout(resolve, 300))
7252
+ ]);
7253
+ }
7232
7254
  store.dispatch({ type: "leave" });
7233
7255
  await dropRoom();
7234
7256
  options.onLeft?.(null);
@@ -7324,8 +7346,6 @@ function createRoomEngine(options) {
7324
7346
  },
7325
7347
  participantLeft(who, reason) {
7326
7348
  departures.set(who, reason);
7327
- liveness.forget(who);
7328
- silent.delete(who);
7329
7349
  },
7330
7350
  roomMetadata(metadata) {
7331
7351
  let parsed = {};
@@ -7368,8 +7388,12 @@ function createRoomEngine(options) {
7368
7388
  const snap = store.snapshot();
7369
7389
  if (snap.phase !== "in_call" || snap.connection !== "stable") return;
7370
7390
  startHealth();
7391
+ const before = assessor.current();
7371
7392
  const quality = assessor.push(reading);
7372
7393
  const path = pathOf(reading);
7394
+ if (quality !== before) {
7395
+ report("info", `meet: this connection reads ${quality} (round trip ${reading.rttMs ?? "?"} ms, path ${path})`, "Diagnostic only.");
7396
+ }
7373
7397
  patchLocalNetwork({ quality, ...path !== "unknown" ? { path } : {} });
7374
7398
  refreshQualities();
7375
7399
  const cameraOn = snap.media.camera.enabled;
@@ -7384,6 +7408,11 @@ function createRoomEngine(options) {
7384
7408
  connectionState(state) {
7385
7409
  supervisor.driverState(state);
7386
7410
  if (state === "connected" && store.snapshot().phase === "joining") store.dispatch({ type: "connected" });
7411
+ if (state === "connected") {
7412
+ startHealth();
7413
+ lastBeatAt = 0;
7414
+ healthTick();
7415
+ }
7387
7416
  },
7388
7417
  transcription(event) {
7389
7418
  const snapshot = store.snapshot();
@@ -7475,6 +7504,10 @@ function createRoomEngine(options) {
7475
7504
  }
7476
7505
  const sender = personOf(from ?? "");
7477
7506
  if (from !== null) {
7507
+ if (topic === ALIVE_TOPIC && isBye(payload)) {
7508
+ saidBye.add(from);
7509
+ return;
7510
+ }
7478
7511
  const beat = topic === ALIVE_TOPIC ? decodeBeat(payload) : null;
7479
7512
  const before = liveness.reported(from);
7480
7513
  liveness.heard(from, beat);
@@ -7589,6 +7622,7 @@ function createRoomEngine(options) {
7589
7622
  current = token;
7590
7623
  lastServerUrl = token.serverUrl;
7591
7624
  connectionPolicy = token.connectionPolicy ?? DEFAULT_CONNECTION_POLICY;
7625
+ store.patch({ captionsStartTimeoutSeconds: connectionPolicy.captionsStartTimeoutSeconds });
7592
7626
  if (token.leavePolicy !== void 0) store.patch({ leavePolicy: token.leavePolicy });
7593
7627
  store.patch({ canReclaim: token.canReclaim === true });
7594
7628
  store.patch({
@@ -7706,10 +7740,17 @@ function createRoomEngine(options) {
7706
7740
  const graceMs = connectionPolicy.reconnectGraceSeconds * 1e3;
7707
7741
  for (const [who, reason] of departures) {
7708
7742
  const last = previous.get(who);
7709
- if (last !== void 0 && !last.isLocal && !present.has(who) && graceMs > 0 && isUnannouncedDeparture(reason)) {
7743
+ const dropped = !saidBye.has(who) && (isUnannouncedDeparture(reason) || silent.has(who));
7744
+ report("info", `meet: ${who} left the room (${reason ?? "no reason"}${dropped ? ", held as reconnecting" : ""})`, "Diagnostic only.");
7745
+ if (last !== void 0 && !last.isLocal && !present.has(who) && graceMs > 0 && dropped) {
7710
7746
  ghosts.set(who, { participant: last, until: at + graceMs });
7711
7747
  }
7712
7748
  }
7749
+ for (const who of departures.keys()) {
7750
+ liveness.forget(who);
7751
+ silent.delete(who);
7752
+ saidBye.delete(who);
7753
+ }
7713
7754
  departures.clear();
7714
7755
  liveRoster = list;
7715
7756
  const localNow = list.find((p) => p.isLocal);