@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/dist/index.d.cts CHANGED
@@ -796,10 +796,10 @@ declare function unavailableFrom(error: MeetError): MediaUnavailable;
796
796
  */
797
797
  declare const LISTEN_ONLY_NOTICE = "You're attending without a microphone \u2014 others can't hear you";
798
798
  /**
799
- * True when this participant is in the room and publishing no microphone —
800
- * whether the device was refused or simply turned off. Both are listen-only,
801
- * and both deserve the same honest line; only the REMEDY differs, and that
802
- * comes from `media.microphone.unavailable`.
799
+ * True when this participant is in the room with NO USABLE microphone — the
800
+ * device was refused or is missing. A person who simply muted themselves has a
801
+ * working microphone and is not "attending without" one, so a mute never
802
+ * counts: `unavailable` is the only signal.
803
803
  */
804
804
  declare function isListenOnly(media: LocalMediaState): boolean;
805
805
  /**
@@ -2408,6 +2408,8 @@ interface MeetRoomDriver {
2408
2408
  setVideoEffect?(effect: VideoEffect): Promise<void>;
2409
2409
  /** Whether this browser can run background effects at all. */
2410
2410
  supportsVideoEffects?(): boolean;
2411
+ /** Whether this browser can share a screen at all (iOS cannot). Absent = assume yes. */
2412
+ supportsScreenShare?(): boolean;
2411
2413
  /**
2412
2414
  * Attach a participant's track to a media element. Returns the detach
2413
2415
  * function — returning it (rather than exposing `detach`) is what makes a
@@ -3463,6 +3465,8 @@ interface RoomEngine {
3463
3465
  setEffects(next: Partial<MediaEffects>): Promise<void>;
3464
3466
  /** Whether this browser can run a background effect at all (absent, never dead). */
3465
3467
  supportsVideoEffects(): boolean;
3468
+ /** Whether this browser can share a screen at all — the control is ABSENT where it cannot. */
3469
+ supportsScreenShare(): boolean;
3466
3470
  /** Choose the speaker (audio output) for this meeting. */
3467
3471
  switchDevice(kind: "audioinput" | "videoinput" | "audiooutput", deviceId: string): Promise<void>;
3468
3472
  pin(identity: ParticipantIdentity | null): void;
package/dist/index.d.ts CHANGED
@@ -796,10 +796,10 @@ declare function unavailableFrom(error: MeetError): MediaUnavailable;
796
796
  */
797
797
  declare const LISTEN_ONLY_NOTICE = "You're attending without a microphone \u2014 others can't hear you";
798
798
  /**
799
- * True when this participant is in the room and publishing no microphone —
800
- * whether the device was refused or simply turned off. Both are listen-only,
801
- * and both deserve the same honest line; only the REMEDY differs, and that
802
- * comes from `media.microphone.unavailable`.
799
+ * True when this participant is in the room with NO USABLE microphone — the
800
+ * device was refused or is missing. A person who simply muted themselves has a
801
+ * working microphone and is not "attending without" one, so a mute never
802
+ * counts: `unavailable` is the only signal.
803
803
  */
804
804
  declare function isListenOnly(media: LocalMediaState): boolean;
805
805
  /**
@@ -2408,6 +2408,8 @@ interface MeetRoomDriver {
2408
2408
  setVideoEffect?(effect: VideoEffect): Promise<void>;
2409
2409
  /** Whether this browser can run background effects at all. */
2410
2410
  supportsVideoEffects?(): boolean;
2411
+ /** Whether this browser can share a screen at all (iOS cannot). Absent = assume yes. */
2412
+ supportsScreenShare?(): boolean;
2411
2413
  /**
2412
2414
  * Attach a participant's track to a media element. Returns the detach
2413
2415
  * function — returning it (rather than exposing `detach`) is what makes a
@@ -3463,6 +3465,8 @@ interface RoomEngine {
3463
3465
  setEffects(next: Partial<MediaEffects>): Promise<void>;
3464
3466
  /** Whether this browser can run a background effect at all (absent, never dead). */
3465
3467
  supportsVideoEffects(): boolean;
3468
+ /** Whether this browser can share a screen at all — the control is ABSENT where it cannot. */
3469
+ supportsScreenShare(): boolean;
3466
3470
  /** Choose the speaker (audio output) for this meeting. */
3467
3471
  switchDevice(kind: "audioinput" | "videoinput" | "audiooutput", deviceId: string): Promise<void>;
3468
3472
  pin(identity: ParticipantIdentity | null): void;
package/dist/index.js CHANGED
@@ -139,6 +139,32 @@ function normalizeDeviceError(error, operation) {
139
139
  );
140
140
  }
141
141
  }
142
+ function isScreenShareCancel(error) {
143
+ const named = (value) => typeof value?.name === "string" ? value.name : "";
144
+ const cause = error instanceof MeetError ? error.cause : void 0;
145
+ const names = [named(error), named(cause)];
146
+ if (names.some((name) => name === "NotAllowedError" || name === "AbortError")) return true;
147
+ return error instanceof MeetError && error.code === "permission-denied";
148
+ }
149
+ function normalizeScreenShareError(error, operation) {
150
+ if (error instanceof MeetError) return error;
151
+ const raw = error ?? {};
152
+ const message = typeof raw.message === "string" ? raw.message : String(error);
153
+ if (isScreenShareCancel(error)) {
154
+ return new MeetError(
155
+ "permission-denied",
156
+ `${operation}: screen sharing was cancelled`,
157
+ "Choose a screen, window or tab in the picker to share it.",
158
+ error
159
+ );
160
+ }
161
+ return new MeetError(
162
+ "media-unsupported",
163
+ `${operation}: screen sharing is not available (${message})`,
164
+ "This browser or device could not share a screen. You are still in the call; try a desktop browser to present.",
165
+ error
166
+ );
167
+ }
142
168
  function invalidResponse(operation, detail) {
143
169
  return new MeetError(
144
170
  "invalid-response",
@@ -2602,7 +2628,7 @@ function unavailableFrom(error) {
2602
2628
  }
2603
2629
  var LISTEN_ONLY_NOTICE = "You're attending without a microphone \u2014 others can't hear you";
2604
2630
  function isListenOnly(media) {
2605
- return !media.microphone.enabled;
2631
+ return !media.microphone.enabled && media.microphone.unavailable !== null;
2606
2632
  }
2607
2633
  function listenOnlyNotice(media) {
2608
2634
  return isListenOnly(media) ? LISTEN_ONLY_NOTICE : null;
@@ -3789,7 +3815,7 @@ function createLiveKitDriver(handlers, options = {}) {
3789
3815
  try {
3790
3816
  await requireRoom("setScreenShareEnabled").localParticipant.setScreenShareEnabled(enabled);
3791
3817
  } catch (error) {
3792
- throw normalizeDeviceError(error, "meet.setScreenShareEnabled");
3818
+ throw normalizeScreenShareError(error, "meet.setScreenShareEnabled");
3793
3819
  }
3794
3820
  },
3795
3821
  async publishData(topic, payload, to) {
@@ -3826,6 +3852,9 @@ function createLiveKitDriver(handlers, options = {}) {
3826
3852
  supportsVideoEffects() {
3827
3853
  return videoEffectsSupported();
3828
3854
  },
3855
+ supportsScreenShare() {
3856
+ return typeof navigator !== "undefined" && typeof navigator.mediaDevices?.getDisplayMedia === "function";
3857
+ },
3829
3858
  attach(identity, kind, element) {
3830
3859
  const target = requireRoom("attach");
3831
3860
  const source = sources?.[kind];
@@ -5276,7 +5305,16 @@ function createRoomEngine(options) {
5276
5305
  try {
5277
5306
  await driver.setScreenShareEnabled(enabled);
5278
5307
  } catch (error) {
5279
- throw fail(error, "meet.setScreenShareEnabled");
5308
+ if (isScreenShareCancel(error)) return;
5309
+ const normalized = normalizeScreenShareError(error, "meet.setScreenShareEnabled");
5310
+ report("warn", normalized.message, normalized.remedy);
5311
+ store.patch({
5312
+ actionNotice: {
5313
+ text: `Screen sharing is not available. ${normalized.remedy}`,
5314
+ failed: true,
5315
+ at: now()
5316
+ }
5317
+ });
5280
5318
  }
5281
5319
  },
5282
5320
  async raiseHand(raised) {
@@ -5324,6 +5362,9 @@ function createRoomEngine(options) {
5324
5362
  supportsVideoEffects() {
5325
5363
  return driver?.supportsVideoEffects?.() ?? false;
5326
5364
  },
5365
+ supportsScreenShare() {
5366
+ return driver?.supportsScreenShare?.() ?? true;
5367
+ },
5327
5368
  async switchDevice(kind, deviceId) {
5328
5369
  if (driver === null) return;
5329
5370
  await driver.switchDevice(kind, deviceId);