@ai-matrx/meet 0.11.49 → 0.11.50

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/react.cjs CHANGED
@@ -4778,7 +4778,10 @@ function createMeetingSession(options) {
4778
4778
  const meeting = store.snapshot().meeting;
4779
4779
  const pass = options.resolvePass?.() ?? null;
4780
4780
  if (meeting === null || pass === null) return;
4781
- if (policyReading) return policyInFlight ?? void 0;
4781
+ if (policyReading) {
4782
+ await (policyInFlight ?? void 0);
4783
+ return readLivePolicy();
4784
+ }
4782
4785
  policyReading = true;
4783
4786
  let done = () => void 0;
4784
4787
  policyInFlight = new Promise((resolve) => done = resolve);
@@ -4799,6 +4802,9 @@ function createMeetingSession(options) {
4799
4802
  if (!samePolicy(snapshot.livePolicy, next) || startedAt !== snapshot.sessionStartedAt) {
4800
4803
  store.patch({ livePolicy: next, sessionStartedAt: startedAt });
4801
4804
  }
4805
+ if (read.consent_given === true && !store.snapshot().recordingConsentGiven) {
4806
+ store.patch({ recordingConsentGiven: true });
4807
+ }
4802
4808
  } catch {
4803
4809
  } finally {
4804
4810
  policyReading = false;
@@ -5103,6 +5109,21 @@ function createMeetingSession(options) {
5103
5109
  stopWaiting,
5104
5110
  readState: readState2,
5105
5111
  readLivePolicy,
5112
+ async acknowledgeConsent() {
5113
+ const meeting = requireMeeting("meet.consent");
5114
+ const pass = options.resolvePass?.() ?? null;
5115
+ const response = await options.api.request({
5116
+ path: MEET_ROUTES.consent,
5117
+ method: "POST",
5118
+ requireAuth: false,
5119
+ operation: "meet.consent",
5120
+ body: { meeting_id: meeting.id },
5121
+ ...pass !== null ? { headers: { [MEETING_PASS_HEADER]: pass } } : {}
5122
+ });
5123
+ if (!response.ok) {
5124
+ throw new MeetError("transport", `meet.consent: the server answered ${response.status}`, "Your agreement was not saved. Try again.");
5125
+ }
5126
+ },
5106
5127
  async readExit(connection, held) {
5107
5128
  const meeting = store.snapshot().meeting;
5108
5129
  const pass = held ?? options.resolvePass?.() ?? null;
@@ -5498,7 +5519,9 @@ function createMediaSupervisor(options) {
5498
5519
  const deviceKind = INPUT_KIND[kind];
5499
5520
  const previous = inUse[deviceKind];
5500
5521
  const track = store.snapshot().media[kind];
5501
- const gone = previous !== null && !isAlias(previous) && before[deviceKind].has(previous) && !now[deviceKind].has(previous);
5522
+ const aliasLabel = previous !== null && isAlias(previous) ? before[deviceKind].get(previous) : void 0;
5523
+ const aliasGone = previous !== null && aliasLabel !== void 0 && aliasLabel !== "" && (!now[deviceKind].has(previous) || now[deviceKind].get(previous) !== aliasLabel);
5524
+ const gone = aliasGone || previous !== null && !isAlias(previous) && before[deviceKind].has(previous) && !now[deviceKind].has(previous);
5502
5525
  if (gone) {
5503
5526
  const from = before[deviceKind].get(previous) ?? "";
5504
5527
  const remaining = [...now[deviceKind].entries()].filter(([id]) => !isAlias(id));
@@ -5523,7 +5546,7 @@ function createMediaSupervisor(options) {
5523
5546
  await driver.setCameraEnabled(true);
5524
5547
  store.setLocalTrack("camera", { enabled: true, unavailable: null });
5525
5548
  }
5526
- setRegion({ notice: { id: ++noticeId, kind, outcome: "switched", from, to: nextLabel } });
5549
+ setRegion({ notice: { id: ++noticeId, kind, outcome: "switched", from, fromId: previous, to: nextLabel } });
5527
5550
  } catch (error) {
5528
5551
  const refused = await unavailable(error, "camera", "meet.camera(fallback)");
5529
5552
  store.setLocalTrack("camera", { enabled: false, unavailable: refused });
@@ -5531,8 +5554,24 @@ function createMediaSupervisor(options) {
5531
5554
  }
5532
5555
  } else {
5533
5556
  const active = driver.activeDevices().audioinput;
5534
- const to = (active !== null ? now.audioinput.get(active) : void 0) ?? now.audioinput.get("default") ?? remaining[0][1];
5535
- setRegion({ notice: { id: ++noticeId, kind, outcome: "switched", from, to } });
5557
+ let to = (active !== null && !aliasGone ? now.audioinput.get(active) : void 0) ?? now.audioinput.get("default");
5558
+ if (to === void 0 || aliasGone) {
5559
+ const [nextId, nextLabel] = remaining[0];
5560
+ try {
5561
+ await driver.switchDevice("audioinput", nextId);
5562
+ if (track.enabled || track.unavailable !== null) {
5563
+ await driver.setMicrophoneEnabled(true);
5564
+ store.setLocalTrack("microphone", { enabled: true, unavailable: null });
5565
+ }
5566
+ to = nextLabel;
5567
+ } catch (error) {
5568
+ const refused = await unavailable(error, "microphone", "meet.microphone(fallback)");
5569
+ store.setLocalTrack("microphone", { enabled: false, unavailable: refused });
5570
+ setRegion({ notice: { id: ++noticeId, kind, outcome: "lost", from, to: null } });
5571
+ continue;
5572
+ }
5573
+ }
5574
+ setRegion({ notice: { id: ++noticeId, kind, outcome: "switched", from, fromId: previous, to } });
5536
5575
  }
5537
5576
  continue;
5538
5577
  }
@@ -5637,6 +5676,21 @@ function createMediaSupervisor(options) {
5637
5676
  },
5638
5677
  dismissNotice() {
5639
5678
  setRegion({ notice: null });
5679
+ },
5680
+ async undoNotice() {
5681
+ const notice = region().notice;
5682
+ setRegion({ notice: null });
5683
+ const driver = options.driver();
5684
+ if (notice === null || notice.outcome !== "switched" || notice.fromId === void 0 || driver === null) return;
5685
+ const list = await snapshotDevices();
5686
+ if (!list[INPUT_KIND[notice.kind]].has(notice.fromId)) return;
5687
+ try {
5688
+ await driver.switchDevice(INPUT_KIND[notice.kind], notice.fromId);
5689
+ readInUse();
5690
+ } catch (error) {
5691
+ const refused = await unavailable(error, notice.kind, "meet.undoDeviceSwitch");
5692
+ store.setLocalTrack(notice.kind, { enabled: false, unavailable: refused });
5693
+ }
5640
5694
  }
5641
5695
  };
5642
5696
  return api;
@@ -5859,11 +5913,10 @@ function moderationText(kind, payload) {
5859
5913
  switch (kind) {
5860
5914
  case "muted": {
5861
5915
  const source = text2(payload["source"]) ?? "microphone";
5862
- const who = payload["by_role"] === "host" || payload["by_role"] === "cohost" ? "the host" : by;
5863
- return source === "microphone" ? `You've been muted by ${who}.` : source === "camera" ? `Your camera was turned off by ${who}.` : `Your screen share was stopped by ${who}.`;
5916
+ return source === "microphone" ? `${by} muted you.` : source === "camera" ? `${by} turned off your camera.` : `${by} stopped your screen share.`;
5864
5917
  }
5865
5918
  case "ask-unmute":
5866
- return `${by === "The host" ? "The host" : by} asked you to unmute.`;
5919
+ return `${by} is asking you to unmute.`;
5867
5920
  case "removed":
5868
5921
  return `${by} removed you from this meeting.`;
5869
5922
  default:
@@ -5889,7 +5942,7 @@ function applyModeration(store, payload, now) {
5889
5942
  grants: { ...snapshot.grants, role },
5890
5943
  moderationNotice: {
5891
5944
  kind: "role",
5892
- text: role === "host" ? "You are now the host." : role === "cohost" ? "You're now a co-host." : role === "presenter" ? "You're now a presenter." : snapshot.grants.role === "presenter" ? "You're now a participant: you can no longer present." : "You're now a participant: you are no longer a co-host.",
5945
+ text: role === "host" ? "You are now the host." : role === "cohost" ? "You are now a co-host." : role === "presenter" ? "You are now a presenter." : snapshot.grants.role === "presenter" ? "You are now a participant: you can no longer present." : "You are no longer a co-host.",
5893
5946
  at: now()
5894
5947
  }
5895
5948
  });
@@ -6391,7 +6444,14 @@ function createRoomEngine(options) {
6391
6444
  const latest = store.snapshot().meeting;
6392
6445
  if (latest === null) return;
6393
6446
  store.patch({ meeting: { ...latest, endedAt: verified.endedAt } });
6394
- store.dispatch({ type: "ended" }, { reason: "ended" });
6447
+ const connection = current?.connectionIdentity ?? current?.identity ?? store.snapshot().localIdentity ?? null;
6448
+ let why;
6449
+ try {
6450
+ why = options.readExit !== void 0 && connection !== null ? await options.readExit(connection, current?.meetingPass ?? null) : void 0;
6451
+ } catch {
6452
+ why = null;
6453
+ }
6454
+ store.dispatch({ type: "ended" }, { reason: why?.exitReason === "time_limit" ? "time_limit" : "ended" });
6395
6455
  await dropRoom();
6396
6456
  options.onLeft?.("ended");
6397
6457
  } catch (error) {
@@ -7163,6 +7223,7 @@ function createRoomEngine(options) {
7163
7223
  acceptDeviceOffer: () => media.acceptOffer(),
7164
7224
  dismissDeviceOffer: () => media.dismissOffer(),
7165
7225
  dismissDeviceNotice: () => media.dismissNotice(),
7226
+ undoDeviceNotice: () => media.undoNotice(),
7166
7227
  pin(who) {
7167
7228
  store.patch({ pinned: who, layout: who === null ? "grid" : "speaker" });
7168
7229
  },
@@ -9735,6 +9796,7 @@ function useMediaSupervisor() {
9735
9796
  acceptOffer: (0, import_react4.useCallback)(async () => engine?.acceptDeviceOffer(), [engine]),
9736
9797
  dismissOffer: (0, import_react4.useCallback)(() => engine?.dismissDeviceOffer(), [engine]),
9737
9798
  dismissNotice: (0, import_react4.useCallback)(() => engine?.dismissDeviceNotice(), [engine]),
9799
+ undoNotice: (0, import_react4.useCallback)(async () => engine?.undoDeviceNotice(), [engine]),
9738
9800
  retry: (0, import_react4.useCallback)(
9739
9801
  async (kind) => kind === "microphone" ? engine?.setMicrophoneEnabled(true) : engine?.setCameraEnabled(true),
9740
9802
  [engine]
@@ -10204,19 +10266,19 @@ function useLivePolicy() {
10204
10266
  const host = useMeetHost();
10205
10267
  const pending = consentPending(policy, role, snapshot?.recording === "recording", snapshot?.recordingConsentGiven === true);
10206
10268
  const viewOnly = pending && policy.recordingConsent === "view_only_until_agree";
10207
- const idle = snapshot !== null && snapshot.recording !== "recording" && snapshot.recording !== "starting" && snapshot.recording !== "stopping";
10208
- const given = snapshot?.recordingConsentGiven === true;
10209
10269
  const store = host?.store ?? null;
10210
- (0, import_react4.useEffect)(() => {
10211
- if (idle && given) store?.patch({ recordingConsentGiven: false });
10212
- }, [idle, given, store]);
10213
10270
  return {
10214
10271
  canChat: canChat(policy, role),
10215
10272
  chatMode: policy.chatMode,
10216
10273
  micLocked: isLockedFor(policy, role, "microphone") || viewOnly,
10217
10274
  cameraLocked: isLockedFor(policy, role, "camera") || viewOnly,
10218
10275
  consent: pending ? policy.recordingConsent === "ok_or_leave" ? "ok_or_leave" : "view_only_until_agree" : null,
10219
- agree: () => store?.patch({ recordingConsentGiven: true }),
10276
+ // The person's agreement is recorded by the SERVER (per run); the screen follows at once and
10277
+ // takes it back if the server did not save it.
10278
+ agree: () => {
10279
+ store?.patch({ recordingConsentGiven: true });
10280
+ void host?.meetings.acknowledgeConsent().catch(() => store?.patch({ recordingConsentGiven: false }));
10281
+ },
10220
10282
  minutesLeft: left,
10221
10283
  timeWarning: left !== null && left <= policy.timeLimitWarningMinutes
10222
10284
  };
@@ -13015,7 +13077,7 @@ function SpeakingWhileMutedNudge() {
13015
13077
  }
13016
13078
  function MediaNotices() {
13017
13079
  const media = useLocalMedia();
13018
- const { region, where, enableAudio, acceptOffer, dismissOffer, dismissNotice, retry } = useMediaSupervisor();
13080
+ const { region, where, enableAudio, acceptOffer, dismissOffer, dismissNotice, undoNotice, retry } = useMediaSupervisor();
13019
13081
  const [fixing, setFixing] = (0, import_react10.useState)(null);
13020
13082
  const chips = ["microphone", "camera"].flatMap((kind) => {
13021
13083
  const reason = deviceUnavailableReason(media[kind], region.permission[kind]);
@@ -13080,9 +13142,10 @@ function MediaNotices() {
13080
13142
  {
13081
13143
  className: "mx-meet__media-pill",
13082
13144
  role: "status",
13083
- ...notice.outcome === "lost" ? { "data-meet-notice": "device-lost" } : {},
13145
+ "data-meet-notice": notice.outcome === "lost" ? "device-lost" : "device-switched",
13084
13146
  children: [
13085
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: notice.outcome === "switched" ? `${notice.from || name(notice.kind)} disconnected \xB7 now using ${notice.to || "the default"}` : `${notice.from || name(notice.kind)} disconnected` }),
13147
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: notice.outcome === "switched" ? `${notice.from || name(notice.kind)} disconnected \xB7 switched to ${notice.to || "the default"}` : `${notice.from || name(notice.kind)} disconnected` }),
13148
+ notice.outcome === "switched" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "mx-meet__link", onClick: () => void undoNotice(), children: "Undo" }) : null,
13086
13149
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "mx-meet__toast-close", "aria-label": "Dismiss", onClick: dismissNotice, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CloseIcon, { width: 14, height: 14 }) })
13087
13150
  ]
13088
13151
  }
@@ -13135,7 +13198,7 @@ function MeetingOverlays() {
13135
13198
  live.minutesLeft,
13136
13199
  " ",
13137
13200
  live.minutesLeft === 1 ? "minute" : "minutes",
13138
- " (time limit)."
13201
+ "."
13139
13202
  ] }) : null,
13140
13203
  notice !== null && notice.kind !== "removed" ? (
13141
13204
  // A host's request ("the host is asking you to unmute"), not an error: