@ai-matrx/meet 0.7.79 → 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/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,32 @@ function normalizeDeviceError(error, operation) {
159
159
  );
160
160
  }
161
161
  }
162
+ function isScreenShareCancel(error) {
163
+ const named = (value) => typeof value?.name === "string" ? value.name : "";
164
+ const cause = error instanceof MeetError ? error.cause : void 0;
165
+ const names = [named(error), named(cause)];
166
+ if (names.some((name) => name === "NotAllowedError" || name === "AbortError")) return true;
167
+ return error instanceof MeetError && error.code === "permission-denied";
168
+ }
169
+ function normalizeScreenShareError(error, operation) {
170
+ if (error instanceof MeetError) return error;
171
+ const raw = error ?? {};
172
+ const message = typeof raw.message === "string" ? raw.message : String(error);
173
+ if (isScreenShareCancel(error)) {
174
+ return new MeetError(
175
+ "permission-denied",
176
+ `${operation}: screen sharing was cancelled`,
177
+ "Choose a screen, window or tab in the picker to share it.",
178
+ error
179
+ );
180
+ }
181
+ return new MeetError(
182
+ "media-unsupported",
183
+ `${operation}: screen sharing is not available (${message})`,
184
+ "This browser or device could not share a screen. You are still in the call; try a desktop browser to present.",
185
+ error
186
+ );
187
+ }
162
188
  function invalidResponse(operation, detail) {
163
189
  return new MeetError(
164
190
  "invalid-response",
@@ -1526,7 +1552,7 @@ function unavailableFrom(error) {
1526
1552
  }
1527
1553
  var LISTEN_ONLY_NOTICE = "You're attending without a microphone \u2014 others can't hear you";
1528
1554
  function isListenOnly(media) {
1529
- return !media.microphone.enabled;
1555
+ return !media.microphone.enabled && media.microphone.unavailable !== null;
1530
1556
  }
1531
1557
  function listenOnlyNotice(media) {
1532
1558
  return isListenOnly(media) ? LISTEN_ONLY_NOTICE : null;
@@ -4403,7 +4429,16 @@ function createRoomEngine(options) {
4403
4429
  try {
4404
4430
  await driver.setScreenShareEnabled(enabled);
4405
4431
  } catch (error) {
4406
- throw fail(error, "meet.setScreenShareEnabled");
4432
+ if (isScreenShareCancel(error)) return;
4433
+ const normalized = normalizeScreenShareError(error, "meet.setScreenShareEnabled");
4434
+ report("warn", normalized.message, normalized.remedy);
4435
+ store.patch({
4436
+ actionNotice: {
4437
+ text: `Screen sharing is not available. ${normalized.remedy}`,
4438
+ failed: true,
4439
+ at: now()
4440
+ }
4441
+ });
4407
4442
  }
4408
4443
  },
4409
4444
  async raiseHand(raised) {
@@ -4451,6 +4486,9 @@ function createRoomEngine(options) {
4451
4486
  supportsVideoEffects() {
4452
4487
  return driver?.supportsVideoEffects?.() ?? false;
4453
4488
  },
4489
+ supportsScreenShare() {
4490
+ return driver?.supportsScreenShare?.() ?? true;
4491
+ },
4454
4492
  async switchDevice(kind, deviceId2) {
4455
4493
  if (driver === null) return;
4456
4494
  await driver.switchDevice(kind, deviceId2);
@@ -5020,7 +5058,7 @@ function createLiveKitDriver(handlers, options = {}) {
5020
5058
  try {
5021
5059
  await requireRoom("setScreenShareEnabled").localParticipant.setScreenShareEnabled(enabled);
5022
5060
  } catch (error) {
5023
- throw normalizeDeviceError(error, "meet.setScreenShareEnabled");
5061
+ throw normalizeScreenShareError(error, "meet.setScreenShareEnabled");
5024
5062
  }
5025
5063
  },
5026
5064
  async publishData(topic, payload, to) {
@@ -5057,6 +5095,9 @@ function createLiveKitDriver(handlers, options = {}) {
5057
5095
  supportsVideoEffects() {
5058
5096
  return videoEffectsSupported();
5059
5097
  },
5098
+ supportsScreenShare() {
5099
+ return typeof navigator !== "undefined" && typeof navigator.mediaDevices?.getDisplayMedia === "function";
5100
+ },
5060
5101
  attach(identity, kind, element) {
5061
5102
  const target = requireRoom("attach");
5062
5103
  const source = sources?.[kind];
@@ -6166,6 +6207,7 @@ function useRoom() {
6166
6207
  participants: snapshot?.participants ?? [],
6167
6208
  failure: snapshot?.failure ?? null,
6168
6209
  local,
6210
+ canShareScreen: engine?.supportsScreenShare() ?? true,
6169
6211
  join: useCallback2(
6170
6212
  async (request) => requireEngine(engine, "join").join(request),
6171
6213
  [engine]
@@ -6979,6 +7021,7 @@ import {
6979
7021
  import { avatarPaletteIndex, formatDurationMs as formatDurationMs4, getInitials } from "@ai-matrx/kit/format";
6980
7022
 
6981
7023
  // src/core/after.ts
7024
+ import { toDelimited } from "@ai-matrx/kit/delimited";
6982
7025
  import { formatDurationMs as formatDurationMs2 } from "@ai-matrx/kit/format";
6983
7026
  function kindOf(person) {
6984
7027
  if (person.isAgent) return "assistant";
@@ -7117,11 +7160,6 @@ function attendanceTotals(rows) {
7117
7160
  averageMs: timed.length === 0 ? null : Math.round(timed.reduce((sum, row) => sum + (row.durationMs ?? 0), 0) / timed.length)
7118
7161
  };
7119
7162
  }
7120
- function csvCell(value) {
7121
- if (value === null) return "";
7122
- const text3 = String(value);
7123
- return /[",\n\r]/.test(text3) ? `"${text3.replace(/"/g, '""')}"` : text3;
7124
- }
7125
7163
  var ATTENDANCE_CSV_HEADER = [
7126
7164
  "Meeting",
7127
7165
  "Meeting started",
@@ -7133,11 +7171,11 @@ var ATTENDANCE_CSV_HEADER = [
7133
7171
  "Admission"
7134
7172
  ];
7135
7173
  function attendanceCsv(reports) {
7136
- const lines = [ATTENDANCE_CSV_HEADER.join(",")];
7137
- for (const { meeting, rows } of reports) {
7138
- for (const row of rows) {
7139
- lines.push(
7140
- [
7174
+ return toDelimited(
7175
+ [
7176
+ ATTENDANCE_CSV_HEADER,
7177
+ ...reports.flatMap(
7178
+ ({ meeting, rows }) => rows.map((row) => [
7141
7179
  meeting.title,
7142
7180
  meeting.startedAt ?? meeting.scheduledFor,
7143
7181
  row.name,
@@ -7146,12 +7184,11 @@ function attendanceCsv(reports) {
7146
7184
  row.leftAt,
7147
7185
  row.durationMs === null ? null : Math.round(row.durationMs / 6e3) / 10,
7148
7186
  row.admission
7149
- ].map(csvCell).join(",")
7150
- );
7151
- }
7152
- }
7153
- return `${lines.join("\r\n")}\r
7154
- `;
7187
+ ])
7188
+ )
7189
+ ],
7190
+ { lineEnding: "\r\n", trailingNewline: true }
7191
+ );
7155
7192
  }
7156
7193
  function recordingOffsetMs(at, recording) {
7157
7194
  if (recording === null || recording.state !== "available") return null;
@@ -7483,11 +7520,7 @@ function PhoneIcon(props) {
7483
7520
  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" }) });
7484
7521
  }
7485
7522
  function PhoneOffIcon(props) {
7486
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
7487
- /* @__PURE__ */ jsx2("path", { d: "M2 2l20 20" }),
7488
- /* @__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" }),
7489
- /* @__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" })
7490
- ] });
7523
+ 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" }) });
7491
7524
  }
7492
7525
  function HandIcon(props) {
7493
7526
  return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
@@ -8928,7 +8961,7 @@ function ControlBar({ onLeave }) {
8928
8961
  children: room.local?.cameraEnabled === true ? /* @__PURE__ */ jsx4(CameraIcon, {}) : /* @__PURE__ */ jsx4(CameraOffIcon, {})
8929
8962
  }
8930
8963
  ),
8931
- /* @__PURE__ */ jsx4(
8964
+ room.canShareScreen || room.local?.screenSharing === true ? /* @__PURE__ */ jsx4(
8932
8965
  ControlButton,
8933
8966
  {
8934
8967
  label: room.local?.screenSharing === true ? "Stop sharing" : "Share screen",
@@ -8936,7 +8969,7 @@ function ControlBar({ onLeave }) {
8936
8969
  onClick: () => void room.toggleScreenShare(),
8937
8970
  children: /* @__PURE__ */ jsx4(ScreenShareIcon, {})
8938
8971
  }
8939
- ),
8972
+ ) : null,
8940
8973
  /* @__PURE__ */ jsxs3("span", { className: "mx-meet__anchor", children: [
8941
8974
  /* @__PURE__ */ jsx4(
8942
8975
  ControlButton,