@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/CHANGELOG.md +33 -0
- package/dist/index.cjs +68 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +68 -3
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +72 -10
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +6 -0
- package/dist/react.d.ts +6 -0
- package/dist/react.js +72 -10
- package/dist/react.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# Changelog — `@ai-matrx/meet`
|
|
2
2
|
|
|
3
|
+
## 0.7.82
|
|
4
|
+
|
|
5
|
+
- Screen share: a SYSTEM or POLICY block (Chrome/Edge "Permission denied by system", a
|
|
6
|
+
permissions-policy / `display-capture` block, SecurityError) now shows a short notice with the
|
|
7
|
+
remedy (macOS Screen Recording, administrator) and the person stays in the call. A plain
|
|
8
|
+
`NotAllowedError` is a closed picker in Chrome but is indistinguishable from a block in Firefox and
|
|
9
|
+
Safari, so the first one stays silent and the second in a row shows the same notice. New
|
|
10
|
+
`classifyScreenShareError`; `isScreenShareCancel` is now true only for the ambiguous case.
|
|
11
|
+
- Guards: `in-call-phase-guard.test.ts` fails if any action other than join / rejoin / moveToBreakout
|
|
12
|
+
can call `fail()`; the real `supportsScreenShare` browser check is tested in `livekit-driver.test.ts`.
|
|
13
|
+
|
|
14
|
+
**Consumer action:** none.
|
|
15
|
+
|
|
16
|
+
## 0.7.81
|
|
17
|
+
|
|
18
|
+
**Three live defects, one class: an in-call action never changes the call phase.**
|
|
19
|
+
|
|
20
|
+
- Screen share: closing the browser's picker is silent (the person stays in the call, no
|
|
21
|
+
notice); a real failure shows a short notice through the room's existing action toast. The
|
|
22
|
+
engine no longer stamps `failed` for an in-call action, which had thrown a live meeting back to
|
|
23
|
+
"Ready to join?" with a camera/microphone sentence and left a stale tile on the host's grid.
|
|
24
|
+
`RoomEngine.supportsScreenShare()` / `useRoom().canShareScreen` / optional driver
|
|
25
|
+
`supportsScreenShare()` — the Share screen control is absent where the browser has no
|
|
26
|
+
`getDisplayMedia` (iOS). New `isScreenShareCancel`, `normalizeScreenShareError` in `core/errors`.
|
|
27
|
+
- `isListenOnly` / `listenOnlyNotice`: the "attending without a microphone" banner is only for a
|
|
28
|
+
microphone that was REFUSED or missing (`unavailable !== null`). Muting, or joining muted by
|
|
29
|
+
choice, no longer shows it.
|
|
30
|
+
- `PhoneOffIcon` redrawn as the filled call-end handset (the old drawing had a wrong-way slash and
|
|
31
|
+
a garbage path). New `react/icons.test.tsx` validates every icon's geometry.
|
|
32
|
+
|
|
33
|
+
**Consumer action:** none. A host rendering its own banner from `isListenOnly` now gets `false`
|
|
34
|
+
for a self-mute.
|
|
35
|
+
|
|
3
36
|
## 0.7.80
|
|
4
37
|
|
|
5
38
|
- `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,55 @@ function normalizeDeviceError(error, operation) {
|
|
|
350
350
|
);
|
|
351
351
|
}
|
|
352
352
|
}
|
|
353
|
+
var SYSTEM_BLOCK = /by system|permissions?[- ]policy|display-capture|disallowed|not allowed by the system/i;
|
|
354
|
+
function classifyScreenShareError(error) {
|
|
355
|
+
const read = (value, key) => {
|
|
356
|
+
const v = value?.[key];
|
|
357
|
+
return typeof v === "string" ? v : "";
|
|
358
|
+
};
|
|
359
|
+
const cause = error instanceof MeetError ? error.cause : void 0;
|
|
360
|
+
const denied = [error, cause].some((value) => {
|
|
361
|
+
const name = read(value, "name");
|
|
362
|
+
return name === "NotAllowedError" || name === "AbortError" || name === "SecurityError";
|
|
363
|
+
});
|
|
364
|
+
if (denied) {
|
|
365
|
+
const text3 = [read(error, "message"), read(cause, "message")].join(" ");
|
|
366
|
+
return SYSTEM_BLOCK.test(text3) || [error, cause].some((v) => read(v, "name") === "SecurityError") ? "blocked" : "ambiguous";
|
|
367
|
+
}
|
|
368
|
+
if (error instanceof MeetError && error.code === "permission-denied" && cause === void 0) {
|
|
369
|
+
return "ambiguous";
|
|
370
|
+
}
|
|
371
|
+
return "other";
|
|
372
|
+
}
|
|
373
|
+
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.";
|
|
374
|
+
function normalizeScreenShareError(error, operation) {
|
|
375
|
+
if (error instanceof MeetError) return error;
|
|
376
|
+
const raw = error ?? {};
|
|
377
|
+
const message = typeof raw.message === "string" ? raw.message : String(error);
|
|
378
|
+
const kind = classifyScreenShareError(error);
|
|
379
|
+
if (kind === "blocked") {
|
|
380
|
+
return new MeetError(
|
|
381
|
+
"permission-denied",
|
|
382
|
+
`${operation}: screen sharing is blocked (${message})`,
|
|
383
|
+
SCREEN_SHARE_BLOCKED_REMEDY,
|
|
384
|
+
error
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
if (kind === "ambiguous") {
|
|
388
|
+
return new MeetError(
|
|
389
|
+
"permission-denied",
|
|
390
|
+
`${operation}: screen sharing was cancelled or refused`,
|
|
391
|
+
"Choose a screen, window or tab in the picker to share it. If no picker appeared, " + SCREEN_SHARE_BLOCKED_REMEDY,
|
|
392
|
+
error
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
return new MeetError(
|
|
396
|
+
"media-unsupported",
|
|
397
|
+
`${operation}: screen sharing is not available (${message})`,
|
|
398
|
+
"This browser or device could not share a screen. You are still in the call; try a desktop browser to present.",
|
|
399
|
+
error
|
|
400
|
+
);
|
|
401
|
+
}
|
|
353
402
|
function invalidResponse(operation, detail) {
|
|
354
403
|
return new MeetError(
|
|
355
404
|
"invalid-response",
|
|
@@ -2813,7 +2862,7 @@ function unavailableFrom(error) {
|
|
|
2813
2862
|
}
|
|
2814
2863
|
var LISTEN_ONLY_NOTICE = "You're attending without a microphone \u2014 others can't hear you";
|
|
2815
2864
|
function isListenOnly(media) {
|
|
2816
|
-
return !media.microphone.enabled;
|
|
2865
|
+
return !media.microphone.enabled && media.microphone.unavailable !== null;
|
|
2817
2866
|
}
|
|
2818
2867
|
function listenOnlyNotice(media) {
|
|
2819
2868
|
return isListenOnly(media) ? LISTEN_ONLY_NOTICE : null;
|
|
@@ -4000,7 +4049,7 @@ function createLiveKitDriver(handlers, options = {}) {
|
|
|
4000
4049
|
try {
|
|
4001
4050
|
await requireRoom("setScreenShareEnabled").localParticipant.setScreenShareEnabled(enabled);
|
|
4002
4051
|
} catch (error) {
|
|
4003
|
-
throw
|
|
4052
|
+
throw normalizeScreenShareError(error, "meet.setScreenShareEnabled");
|
|
4004
4053
|
}
|
|
4005
4054
|
},
|
|
4006
4055
|
async publishData(topic, payload, to) {
|
|
@@ -4037,6 +4086,9 @@ function createLiveKitDriver(handlers, options = {}) {
|
|
|
4037
4086
|
supportsVideoEffects() {
|
|
4038
4087
|
return videoEffectsSupported();
|
|
4039
4088
|
},
|
|
4089
|
+
supportsScreenShare() {
|
|
4090
|
+
return typeof navigator !== "undefined" && typeof navigator.mediaDevices?.getDisplayMedia === "function";
|
|
4091
|
+
},
|
|
4040
4092
|
attach(identity, kind, element) {
|
|
4041
4093
|
const target = requireRoom("attach");
|
|
4042
4094
|
const source = sources?.[kind];
|
|
@@ -5096,6 +5148,7 @@ function createRoomEngine(options) {
|
|
|
5096
5148
|
function report(level, message, remedy) {
|
|
5097
5149
|
options.onDiagnostic?.(remedy === void 0 ? { level, message } : { level, message, remedy });
|
|
5098
5150
|
}
|
|
5151
|
+
let ambiguousShareDenials = 0;
|
|
5099
5152
|
function fail(error, operation) {
|
|
5100
5153
|
const normalized = normalizeMeetError(error, operation);
|
|
5101
5154
|
store.patch({
|
|
@@ -5486,8 +5539,17 @@ function createRoomEngine(options) {
|
|
|
5486
5539
|
if (driver === null) return;
|
|
5487
5540
|
try {
|
|
5488
5541
|
await driver.setScreenShareEnabled(enabled);
|
|
5542
|
+
ambiguousShareDenials = 0;
|
|
5489
5543
|
} catch (error) {
|
|
5490
|
-
|
|
5544
|
+
const kind = classifyScreenShareError(error);
|
|
5545
|
+
if (kind === "ambiguous") {
|
|
5546
|
+
ambiguousShareDenials += 1;
|
|
5547
|
+
if (ambiguousShareDenials < 2) return;
|
|
5548
|
+
}
|
|
5549
|
+
const normalized = normalizeScreenShareError(error, "meet.setScreenShareEnabled");
|
|
5550
|
+
report("warn", normalized.message, normalized.remedy);
|
|
5551
|
+
const text3 = kind === "other" ? `Screen sharing is not available. ${normalized.remedy}` : `Screen sharing did not start. ${SCREEN_SHARE_BLOCKED_REMEDY}`;
|
|
5552
|
+
store.patch({ actionNotice: { text: text3, failed: true, at: now() } });
|
|
5491
5553
|
}
|
|
5492
5554
|
},
|
|
5493
5555
|
async raiseHand(raised) {
|
|
@@ -5535,6 +5597,9 @@ function createRoomEngine(options) {
|
|
|
5535
5597
|
supportsVideoEffects() {
|
|
5536
5598
|
return driver?.supportsVideoEffects?.() ?? false;
|
|
5537
5599
|
},
|
|
5600
|
+
supportsScreenShare() {
|
|
5601
|
+
return driver?.supportsScreenShare?.() ?? true;
|
|
5602
|
+
},
|
|
5538
5603
|
async switchDevice(kind, deviceId) {
|
|
5539
5604
|
if (driver === null) return;
|
|
5540
5605
|
await driver.switchDevice(kind, deviceId);
|