@ai-matrx/meet 0.7.80 → 0.7.82

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.d.cts CHANGED
@@ -174,6 +174,8 @@ interface UseRoomResult {
174
174
  toggleMicrophone: () => Promise<void>;
175
175
  toggleCamera: () => Promise<void>;
176
176
  toggleScreenShare: () => Promise<void>;
177
+ /** False where the browser cannot share a screen at all (iOS): the control is absent. */
178
+ readonly canShareScreen: boolean;
177
179
  toggleHand: () => Promise<void>;
178
180
  react: (emoji: string) => Promise<void>;
179
181
  /** To EVERYONE — saved through the server (Meet wave 2). */
@@ -773,6 +775,10 @@ declare function CameraIcon(props: IconProps): React.ReactElement;
773
775
  declare function CameraOffIcon(props: IconProps): React.ReactElement;
774
776
  declare function ScreenShareIcon(props: IconProps): React.ReactElement;
775
777
  declare function PhoneIcon(props: IconProps): React.ReactElement;
778
+ /**
779
+ * "Call end" — the downward handset on the red leave button (the glyph Meet
780
+ * users recognise). A FILLED shape, so it overrides the line-icon defaults.
781
+ */
776
782
  declare function PhoneOffIcon(props: IconProps): React.ReactElement;
777
783
  declare function HandIcon(props: IconProps): React.ReactElement;
778
784
  declare function ChatIcon(props: IconProps): React.ReactElement;
package/dist/react.d.ts CHANGED
@@ -174,6 +174,8 @@ interface UseRoomResult {
174
174
  toggleMicrophone: () => Promise<void>;
175
175
  toggleCamera: () => Promise<void>;
176
176
  toggleScreenShare: () => Promise<void>;
177
+ /** False where the browser cannot share a screen at all (iOS): the control is absent. */
178
+ readonly canShareScreen: boolean;
177
179
  toggleHand: () => Promise<void>;
178
180
  react: (emoji: string) => Promise<void>;
179
181
  /** To EVERYONE — saved through the server (Meet wave 2). */
@@ -773,6 +775,10 @@ declare function CameraIcon(props: IconProps): React.ReactElement;
773
775
  declare function CameraOffIcon(props: IconProps): React.ReactElement;
774
776
  declare function ScreenShareIcon(props: IconProps): React.ReactElement;
775
777
  declare function PhoneIcon(props: IconProps): React.ReactElement;
778
+ /**
779
+ * "Call end" — the downward handset on the red leave button (the glyph Meet
780
+ * users recognise). A FILLED shape, so it overrides the line-icon defaults.
781
+ */
776
782
  declare function PhoneOffIcon(props: IconProps): React.ReactElement;
777
783
  declare function HandIcon(props: IconProps): React.ReactElement;
778
784
  declare function ChatIcon(props: IconProps): React.ReactElement;
package/dist/react.js CHANGED
@@ -159,6 +159,55 @@ function normalizeDeviceError(error, operation) {
159
159
  );
160
160
  }
161
161
  }
162
+ var SYSTEM_BLOCK = /by system|permissions?[- ]policy|display-capture|disallowed|not allowed by the system/i;
163
+ function classifyScreenShareError(error) {
164
+ const read = (value, key) => {
165
+ const v = value?.[key];
166
+ return typeof v === "string" ? v : "";
167
+ };
168
+ const cause = error instanceof MeetError ? error.cause : void 0;
169
+ const denied = [error, cause].some((value) => {
170
+ const name = read(value, "name");
171
+ return name === "NotAllowedError" || name === "AbortError" || name === "SecurityError";
172
+ });
173
+ if (denied) {
174
+ const text3 = [read(error, "message"), read(cause, "message")].join(" ");
175
+ return SYSTEM_BLOCK.test(text3) || [error, cause].some((v) => read(v, "name") === "SecurityError") ? "blocked" : "ambiguous";
176
+ }
177
+ if (error instanceof MeetError && error.code === "permission-denied" && cause === void 0) {
178
+ return "ambiguous";
179
+ }
180
+ return "other";
181
+ }
182
+ var SCREEN_SHARE_BLOCKED_REMEDY = "Your browser or computer is blocking screen sharing. On a Mac, open System Settings > Privacy & Security > Screen Recording, turn it on for your browser, then restart the browser. On a work computer, ask your administrator. You are still in the call.";
183
+ function normalizeScreenShareError(error, operation) {
184
+ if (error instanceof MeetError) return error;
185
+ const raw = error ?? {};
186
+ const message = typeof raw.message === "string" ? raw.message : String(error);
187
+ const kind = classifyScreenShareError(error);
188
+ if (kind === "blocked") {
189
+ return new MeetError(
190
+ "permission-denied",
191
+ `${operation}: screen sharing is blocked (${message})`,
192
+ SCREEN_SHARE_BLOCKED_REMEDY,
193
+ error
194
+ );
195
+ }
196
+ if (kind === "ambiguous") {
197
+ return new MeetError(
198
+ "permission-denied",
199
+ `${operation}: screen sharing was cancelled or refused`,
200
+ "Choose a screen, window or tab in the picker to share it. If no picker appeared, " + SCREEN_SHARE_BLOCKED_REMEDY,
201
+ error
202
+ );
203
+ }
204
+ return new MeetError(
205
+ "media-unsupported",
206
+ `${operation}: screen sharing is not available (${message})`,
207
+ "This browser or device could not share a screen. You are still in the call; try a desktop browser to present.",
208
+ error
209
+ );
210
+ }
162
211
  function invalidResponse(operation, detail) {
163
212
  return new MeetError(
164
213
  "invalid-response",
@@ -1526,7 +1575,7 @@ function unavailableFrom(error) {
1526
1575
  }
1527
1576
  var LISTEN_ONLY_NOTICE = "You're attending without a microphone \u2014 others can't hear you";
1528
1577
  function isListenOnly(media) {
1529
- return !media.microphone.enabled;
1578
+ return !media.microphone.enabled && media.microphone.unavailable !== null;
1530
1579
  }
1531
1580
  function listenOnlyNotice(media) {
1532
1581
  return isListenOnly(media) ? LISTEN_ONLY_NOTICE : null;
@@ -4012,6 +4061,7 @@ function createRoomEngine(options) {
4012
4061
  function report(level, message, remedy) {
4013
4062
  options.onDiagnostic?.(remedy === void 0 ? { level, message } : { level, message, remedy });
4014
4063
  }
4064
+ let ambiguousShareDenials = 0;
4015
4065
  function fail(error, operation) {
4016
4066
  const normalized = normalizeMeetError(error, operation);
4017
4067
  store.patch({
@@ -4402,8 +4452,17 @@ function createRoomEngine(options) {
4402
4452
  if (driver === null) return;
4403
4453
  try {
4404
4454
  await driver.setScreenShareEnabled(enabled);
4455
+ ambiguousShareDenials = 0;
4405
4456
  } catch (error) {
4406
- throw fail(error, "meet.setScreenShareEnabled");
4457
+ const kind = classifyScreenShareError(error);
4458
+ if (kind === "ambiguous") {
4459
+ ambiguousShareDenials += 1;
4460
+ if (ambiguousShareDenials < 2) return;
4461
+ }
4462
+ const normalized = normalizeScreenShareError(error, "meet.setScreenShareEnabled");
4463
+ report("warn", normalized.message, normalized.remedy);
4464
+ const text3 = kind === "other" ? `Screen sharing is not available. ${normalized.remedy}` : `Screen sharing did not start. ${SCREEN_SHARE_BLOCKED_REMEDY}`;
4465
+ store.patch({ actionNotice: { text: text3, failed: true, at: now() } });
4407
4466
  }
4408
4467
  },
4409
4468
  async raiseHand(raised) {
@@ -4451,6 +4510,9 @@ function createRoomEngine(options) {
4451
4510
  supportsVideoEffects() {
4452
4511
  return driver?.supportsVideoEffects?.() ?? false;
4453
4512
  },
4513
+ supportsScreenShare() {
4514
+ return driver?.supportsScreenShare?.() ?? true;
4515
+ },
4454
4516
  async switchDevice(kind, deviceId2) {
4455
4517
  if (driver === null) return;
4456
4518
  await driver.switchDevice(kind, deviceId2);
@@ -5020,7 +5082,7 @@ function createLiveKitDriver(handlers, options = {}) {
5020
5082
  try {
5021
5083
  await requireRoom("setScreenShareEnabled").localParticipant.setScreenShareEnabled(enabled);
5022
5084
  } catch (error) {
5023
- throw normalizeDeviceError(error, "meet.setScreenShareEnabled");
5085
+ throw normalizeScreenShareError(error, "meet.setScreenShareEnabled");
5024
5086
  }
5025
5087
  },
5026
5088
  async publishData(topic, payload, to) {
@@ -5057,6 +5119,9 @@ function createLiveKitDriver(handlers, options = {}) {
5057
5119
  supportsVideoEffects() {
5058
5120
  return videoEffectsSupported();
5059
5121
  },
5122
+ supportsScreenShare() {
5123
+ return typeof navigator !== "undefined" && typeof navigator.mediaDevices?.getDisplayMedia === "function";
5124
+ },
5060
5125
  attach(identity, kind, element) {
5061
5126
  const target = requireRoom("attach");
5062
5127
  const source = sources?.[kind];
@@ -6166,6 +6231,7 @@ function useRoom() {
6166
6231
  participants: snapshot?.participants ?? [],
6167
6232
  failure: snapshot?.failure ?? null,
6168
6233
  local,
6234
+ canShareScreen: engine?.supportsScreenShare() ?? true,
6169
6235
  join: useCallback2(
6170
6236
  async (request) => requireEngine(engine, "join").join(request),
6171
6237
  [engine]
@@ -7478,11 +7544,7 @@ function PhoneIcon(props) {
7478
7544
  return /* @__PURE__ */ jsx2(Icon, { ...props, children: /* @__PURE__ */ jsx2("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6A19.79 19.79 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.9.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92Z" }) });
7479
7545
  }
7480
7546
  function PhoneOffIcon(props) {
7481
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
7482
- /* @__PURE__ */ jsx2("path", { d: "M2 2l20 20" }),
7483
- /* @__PURE__ */ jsx2("path", { d: "M10.68 13.31a16 16 0 0 0 3.41 2.6l1.27-1.27a2 2 0 0 1 2.11-.45c.9.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.42 19.42 0 0 1-3.33-2.67" }),
7484
- /* @__PURE__ */ jsx2("path", { d: "M5.53 5.53A19.79 19.79 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91" })
7485
- ] });
7547
+ return /* @__PURE__ */ jsx2(Icon, { fill: "currentColor", stroke: "none", ...props, children: /* @__PURE__ */ jsx2("path", { d: "M12 9c-1.6 0-3.15.25-4.6.72v3.1c0 .39-.23.74-.56.9-.98.49-1.87 1.12-2.66 1.85-.18.18-.43.28-.7.28-.28 0-.53-.11-.71-.29L.29 13.08a.99.99 0 0 1-.29-.7c0-.28.11-.53.29-.71C3.34 8.78 7.46 7 12 7s8.66 1.78 11.71 4.67c.18.18.29.43.29.71 0 .28-.11.53-.29.71l-2.48 2.48c-.18.18-.43.29-.71.29-.27 0-.52-.11-.7-.28a11.27 11.27 0 0 0-2.67-1.85.996.996 0 0 1-.56-.9v-3.1C15.15 9.25 13.6 9 12 9Z" }) });
7486
7548
  }
7487
7549
  function HandIcon(props) {
7488
7550
  return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
@@ -8923,7 +8985,7 @@ function ControlBar({ onLeave }) {
8923
8985
  children: room.local?.cameraEnabled === true ? /* @__PURE__ */ jsx4(CameraIcon, {}) : /* @__PURE__ */ jsx4(CameraOffIcon, {})
8924
8986
  }
8925
8987
  ),
8926
- /* @__PURE__ */ jsx4(
8988
+ room.canShareScreen || room.local?.screenSharing === true ? /* @__PURE__ */ jsx4(
8927
8989
  ControlButton,
8928
8990
  {
8929
8991
  label: room.local?.screenSharing === true ? "Stop sharing" : "Share screen",
@@ -8931,7 +8993,7 @@ function ControlBar({ onLeave }) {
8931
8993
  onClick: () => void room.toggleScreenShare(),
8932
8994
  children: /* @__PURE__ */ jsx4(ScreenShareIcon, {})
8933
8995
  }
8934
- ),
8996
+ ) : null,
8935
8997
  /* @__PURE__ */ jsxs3("span", { className: "mx-meet__anchor", children: [
8936
8998
  /* @__PURE__ */ jsx4(
8937
8999
  ControlButton,