@ai-matrx/meet 0.7.80 → 0.7.81

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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog — `@ai-matrx/meet`
2
2
 
3
+ ## 0.7.81
4
+
5
+ **Three live defects, one class: an in-call action never changes the call phase.**
6
+
7
+ - Screen share: closing the browser's picker is silent (the person stays in the call, no
8
+ notice); a real failure shows a short notice through the room's existing action toast. The
9
+ engine no longer stamps `failed` for an in-call action, which had thrown a live meeting back to
10
+ "Ready to join?" with a camera/microphone sentence and left a stale tile on the host's grid.
11
+ `RoomEngine.supportsScreenShare()` / `useRoom().canShareScreen` / optional driver
12
+ `supportsScreenShare()` — the Share screen control is absent where the browser has no
13
+ `getDisplayMedia` (iOS). New `isScreenShareCancel`, `normalizeScreenShareError` in `core/errors`.
14
+ - `isListenOnly` / `listenOnlyNotice`: the "attending without a microphone" banner is only for a
15
+ microphone that was REFUSED or missing (`unavailable !== null`). Muting, or joining muted by
16
+ choice, no longer shows it.
17
+ - `PhoneOffIcon` redrawn as the filled call-end handset (the old drawing had a wrong-way slash and
18
+ a garbage path). New `react/icons.test.tsx` validates every icon's geometry.
19
+
20
+ **Consumer action:** none. A host rendering its own banner from `isListenOnly` now gets `false`
21
+ for a self-mute.
22
+
3
23
  ## 0.7.80
4
24
 
5
25
  - `attendanceCsv` writes through THE one writer, `@ai-matrx/kit/delimited` (AP-2): CRLF records and trailing CRLF unchanged; a name that opens like a formula gets a leading `'`.
package/dist/index.cjs CHANGED
@@ -350,6 +350,32 @@ function normalizeDeviceError(error, operation) {
350
350
  );
351
351
  }
352
352
  }
353
+ function isScreenShareCancel(error) {
354
+ const named = (value) => typeof value?.name === "string" ? value.name : "";
355
+ const cause = error instanceof MeetError ? error.cause : void 0;
356
+ const names = [named(error), named(cause)];
357
+ if (names.some((name) => name === "NotAllowedError" || name === "AbortError")) return true;
358
+ return error instanceof MeetError && error.code === "permission-denied";
359
+ }
360
+ function normalizeScreenShareError(error, operation) {
361
+ if (error instanceof MeetError) return error;
362
+ const raw = error ?? {};
363
+ const message = typeof raw.message === "string" ? raw.message : String(error);
364
+ if (isScreenShareCancel(error)) {
365
+ return new MeetError(
366
+ "permission-denied",
367
+ `${operation}: screen sharing was cancelled`,
368
+ "Choose a screen, window or tab in the picker to share it.",
369
+ error
370
+ );
371
+ }
372
+ return new MeetError(
373
+ "media-unsupported",
374
+ `${operation}: screen sharing is not available (${message})`,
375
+ "This browser or device could not share a screen. You are still in the call; try a desktop browser to present.",
376
+ error
377
+ );
378
+ }
353
379
  function invalidResponse(operation, detail) {
354
380
  return new MeetError(
355
381
  "invalid-response",
@@ -2813,7 +2839,7 @@ function unavailableFrom(error) {
2813
2839
  }
2814
2840
  var LISTEN_ONLY_NOTICE = "You're attending without a microphone \u2014 others can't hear you";
2815
2841
  function isListenOnly(media) {
2816
- return !media.microphone.enabled;
2842
+ return !media.microphone.enabled && media.microphone.unavailable !== null;
2817
2843
  }
2818
2844
  function listenOnlyNotice(media) {
2819
2845
  return isListenOnly(media) ? LISTEN_ONLY_NOTICE : null;
@@ -4000,7 +4026,7 @@ function createLiveKitDriver(handlers, options = {}) {
4000
4026
  try {
4001
4027
  await requireRoom("setScreenShareEnabled").localParticipant.setScreenShareEnabled(enabled);
4002
4028
  } catch (error) {
4003
- throw normalizeDeviceError(error, "meet.setScreenShareEnabled");
4029
+ throw normalizeScreenShareError(error, "meet.setScreenShareEnabled");
4004
4030
  }
4005
4031
  },
4006
4032
  async publishData(topic, payload, to) {
@@ -4037,6 +4063,9 @@ function createLiveKitDriver(handlers, options = {}) {
4037
4063
  supportsVideoEffects() {
4038
4064
  return videoEffectsSupported();
4039
4065
  },
4066
+ supportsScreenShare() {
4067
+ return typeof navigator !== "undefined" && typeof navigator.mediaDevices?.getDisplayMedia === "function";
4068
+ },
4040
4069
  attach(identity, kind, element) {
4041
4070
  const target = requireRoom("attach");
4042
4071
  const source = sources?.[kind];
@@ -5487,7 +5516,16 @@ function createRoomEngine(options) {
5487
5516
  try {
5488
5517
  await driver.setScreenShareEnabled(enabled);
5489
5518
  } catch (error) {
5490
- throw fail(error, "meet.setScreenShareEnabled");
5519
+ if (isScreenShareCancel(error)) return;
5520
+ const normalized = normalizeScreenShareError(error, "meet.setScreenShareEnabled");
5521
+ report("warn", normalized.message, normalized.remedy);
5522
+ store.patch({
5523
+ actionNotice: {
5524
+ text: `Screen sharing is not available. ${normalized.remedy}`,
5525
+ failed: true,
5526
+ at: now()
5527
+ }
5528
+ });
5491
5529
  }
5492
5530
  },
5493
5531
  async raiseHand(raised) {
@@ -5535,6 +5573,9 @@ function createRoomEngine(options) {
5535
5573
  supportsVideoEffects() {
5536
5574
  return driver?.supportsVideoEffects?.() ?? false;
5537
5575
  },
5576
+ supportsScreenShare() {
5577
+ return driver?.supportsScreenShare?.() ?? true;
5578
+ },
5538
5579
  async switchDevice(kind, deviceId) {
5539
5580
  if (driver === null) return;
5540
5581
  await driver.switchDevice(kind, deviceId);