@ai-matrx/meet 0.10.7 → 0.11.1
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 +6 -0
- package/dist/{collab-ytIzjceh.d.cts → collab-CIyXdQ5l.d.cts} +1 -2
- package/dist/{collab-ytIzjceh.d.ts → collab-CIyXdQ5l.d.ts} +1 -2
- package/dist/{components-CnnefQn-.d.cts → components-DUvy3BQf.d.cts} +1 -1
- package/dist/{components-DjzH3u_c.d.ts → components-DiGxfKXI.d.ts} +1 -1
- package/dist/core.cjs +417 -100
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +254 -24
- package/dist/core.d.ts +254 -24
- package/dist/core.js +417 -100
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +417 -100
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +417 -100
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +710 -118
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +68 -7
- package/dist/react.d.ts +68 -7
- package/dist/react.js +711 -119
- package/dist/react.js.map +1 -1
- package/dist/skins/meet.cjs +265 -50
- package/dist/skins/meet.cjs.map +1 -1
- package/dist/skins/meet.d.cts +2 -2
- package/dist/skins/meet.d.ts +2 -2
- package/dist/skins/meet.js +265 -50
- package/dist/skins/meet.js.map +1 -1
- package/dist/styles.css +20 -0
- package/package.json +6 -6
package/dist/react.cjs
CHANGED
|
@@ -49,11 +49,13 @@ __export(react_exports, {
|
|
|
49
49
|
GUEST_RECORD_NOT_SHARED: () => GUEST_RECORD_NOT_SHARED,
|
|
50
50
|
GuestRecordAccessControl: () => GuestRecordAccessControl,
|
|
51
51
|
IDLE_MEDIA: () => IDLE_MEDIA,
|
|
52
|
+
IDLE_PHASES: () => IDLE_PHASES,
|
|
52
53
|
IDLE_TRACK: () => IDLE_TRACK,
|
|
53
54
|
IncomingCallCard: () => IncomingCallCard,
|
|
54
55
|
IncomingCallHost: () => IncomingCallHost,
|
|
55
56
|
JOIN_REFUSAL_REASONS: () => JOIN_REFUSAL_REASONS,
|
|
56
57
|
LISTEN_ONLY_NOTICE: () => LISTEN_ONLY_NOTICE,
|
|
58
|
+
LIVE_PHASES: () => LIVE_PHASES,
|
|
57
59
|
MEETING_INVITE_KIND: () => MEETING_INVITE_KIND,
|
|
58
60
|
MEETING_INVITE_VERSION: () => MEETING_INVITE_VERSION,
|
|
59
61
|
MEETING_PASS_HEADER: () => MEETING_PASS_HEADER,
|
|
@@ -75,6 +77,7 @@ __export(react_exports, {
|
|
|
75
77
|
NOTE_TAKER_IDENTITY_PREFIX: () => NOTE_TAKER_IDENTITY_PREFIX,
|
|
76
78
|
NOTE_TAKER_METADATA_KEY: () => NOTE_TAKER_METADATA_KEY,
|
|
77
79
|
NO_GRANTS: () => NO_GRANTS,
|
|
80
|
+
NO_SHARE: () => NO_SHARE,
|
|
78
81
|
ORGANIZATION_HEADER: () => ORGANIZATION_HEADER,
|
|
79
82
|
PARTICIPANT_CAN_RECORD_ATTRIBUTE: () => PARTICIPANT_CAN_RECORD_ATTRIBUTE,
|
|
80
83
|
PARTICIPANT_ROLE_ATTRIBUTE: () => PARTICIPANT_ROLE_ATTRIBUTE,
|
|
@@ -89,9 +92,11 @@ __export(react_exports, {
|
|
|
89
92
|
TABLES: () => TABLES,
|
|
90
93
|
TRANSCRIPTION_ATTRIBUTES: () => TRANSCRIPTION_ATTRIBUTES,
|
|
91
94
|
TRANSCRIPTION_TOPIC: () => TRANSCRIPTION_TOPIC,
|
|
95
|
+
WAITING_PHASES: () => WAITING_PHASES,
|
|
92
96
|
absenceSentence: () => absenceSentence,
|
|
93
97
|
activeWrapUpSummary: () => activeWrapUpSummary,
|
|
94
98
|
activityAttention: () => activityAttention,
|
|
99
|
+
admissionPhase: () => admissionPhase,
|
|
95
100
|
announceMeeting: () => announceMeeting,
|
|
96
101
|
appPanelOf: () => appPanelOf,
|
|
97
102
|
applyCollabPacket: () => applyCollabPacket,
|
|
@@ -161,10 +166,13 @@ __export(react_exports, {
|
|
|
161
166
|
isJoinRefusalReason: () => isJoinRefusalReason,
|
|
162
167
|
isLinkFollower: () => isLinkFollower,
|
|
163
168
|
isListenOnly: () => isListenOnly,
|
|
169
|
+
isLivePhase: () => isLivePhase,
|
|
164
170
|
isNoteTaker: () => isNoteTaker,
|
|
165
171
|
isObserverRole: () => isObserverRole,
|
|
166
172
|
isRealName: () => isRealName,
|
|
173
|
+
isRefusedPhase: () => isRefusedPhase,
|
|
167
174
|
isRoomEventTopic: () => isRoomEventTopic,
|
|
175
|
+
isWaitingPhase: () => isWaitingPhase,
|
|
168
176
|
learnName: () => learnName,
|
|
169
177
|
learnNames: () => learnNames,
|
|
170
178
|
listenOnlyNotice: () => listenOnlyNotice,
|
|
@@ -189,6 +197,7 @@ __export(react_exports, {
|
|
|
189
197
|
mergeRecord: () => mergeRecord,
|
|
190
198
|
microphoneNoticeCode: () => microphoneNoticeCode,
|
|
191
199
|
moveToRoom: () => moveToRoom,
|
|
200
|
+
nextPhase: () => nextPhase,
|
|
192
201
|
nextTranslationBatch: () => nextTranslationBatch,
|
|
193
202
|
normalizeDeviceError: () => normalizeDeviceError,
|
|
194
203
|
normalizeMeetError: () => normalizeMeetError,
|
|
@@ -221,10 +230,13 @@ __export(react_exports, {
|
|
|
221
230
|
pushMeetingToGoogleCalendar: () => pushMeetingToGoogleCalendar,
|
|
222
231
|
readServerRefusal: () => readServerRefusal,
|
|
223
232
|
readableTranscript: () => readableTranscript,
|
|
233
|
+
reasonOf: () => reasonOf,
|
|
224
234
|
recordingLabel: () => recordingLabel,
|
|
225
235
|
recordingNotice: () => recordingNotice,
|
|
226
236
|
recordingOffsetMs: () => recordingOffsetMs,
|
|
237
|
+
refusalPhase: () => refusalPhase,
|
|
227
238
|
rememberedMeetingPass: () => rememberedMeetingPass,
|
|
239
|
+
resolveExit: () => resolveExit,
|
|
228
240
|
roleOf: () => roleOf,
|
|
229
241
|
roomTopic: () => roomTopic,
|
|
230
242
|
rootAttributes: () => rootAttributes,
|
|
@@ -1291,6 +1303,166 @@ var MEET_EVENTS = {
|
|
|
1291
1303
|
stateChanged: "mx.state.changed"
|
|
1292
1304
|
};
|
|
1293
1305
|
|
|
1306
|
+
// src/core/reasons.ts
|
|
1307
|
+
var JOIN_REFUSAL_REASONS = [
|
|
1308
|
+
"not_found",
|
|
1309
|
+
"cancelled",
|
|
1310
|
+
"ended",
|
|
1311
|
+
"expired",
|
|
1312
|
+
"too_early",
|
|
1313
|
+
"sign_in_required",
|
|
1314
|
+
"wrong_account",
|
|
1315
|
+
"not_invited",
|
|
1316
|
+
"locked",
|
|
1317
|
+
"removed",
|
|
1318
|
+
"lobby_rejects",
|
|
1319
|
+
"meeting_full",
|
|
1320
|
+
"platform_capacity",
|
|
1321
|
+
"verification_required",
|
|
1322
|
+
"registration_required"
|
|
1323
|
+
];
|
|
1324
|
+
function isJoinRefusalReason(value) {
|
|
1325
|
+
return typeof value === "string" && JOIN_REFUSAL_REASONS.includes(value);
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
// src/core/phase.ts
|
|
1329
|
+
var LIVE_PHASES = /* @__PURE__ */ new Set(["joining", "in_call"]);
|
|
1330
|
+
var WAITING_PHASES = /* @__PURE__ */ new Set([
|
|
1331
|
+
"waiting:host_not_started",
|
|
1332
|
+
"waiting:knocking",
|
|
1333
|
+
"denied",
|
|
1334
|
+
"knock_expired"
|
|
1335
|
+
]);
|
|
1336
|
+
var JOINABLE_FROM = /* @__PURE__ */ new Set([
|
|
1337
|
+
"prejoin",
|
|
1338
|
+
"left",
|
|
1339
|
+
"disconnected",
|
|
1340
|
+
"superseded",
|
|
1341
|
+
"inactive",
|
|
1342
|
+
"denied",
|
|
1343
|
+
"knock_expired"
|
|
1344
|
+
]);
|
|
1345
|
+
var NOT_ENDABLE = /* @__PURE__ */ new Set([
|
|
1346
|
+
"ended",
|
|
1347
|
+
"record",
|
|
1348
|
+
"unsupported",
|
|
1349
|
+
"ringing_out",
|
|
1350
|
+
"ringing_in",
|
|
1351
|
+
"call_declined",
|
|
1352
|
+
"call_missed",
|
|
1353
|
+
"call_busy",
|
|
1354
|
+
"answered_elsewhere"
|
|
1355
|
+
]);
|
|
1356
|
+
var RINGING = /* @__PURE__ */ new Set(["ringing_out", "ringing_in"]);
|
|
1357
|
+
var IDLE_PHASES = /* @__PURE__ */ new Set([
|
|
1358
|
+
"resolving",
|
|
1359
|
+
"left",
|
|
1360
|
+
"call_declined",
|
|
1361
|
+
"call_missed",
|
|
1362
|
+
"call_busy",
|
|
1363
|
+
"answered_elsewhere"
|
|
1364
|
+
]);
|
|
1365
|
+
function isLivePhase(phase) {
|
|
1366
|
+
return LIVE_PHASES.has(phase);
|
|
1367
|
+
}
|
|
1368
|
+
function isWaitingPhase(phase) {
|
|
1369
|
+
return WAITING_PHASES.has(phase);
|
|
1370
|
+
}
|
|
1371
|
+
function isRefusedPhase(phase) {
|
|
1372
|
+
return phase.startsWith("refused:");
|
|
1373
|
+
}
|
|
1374
|
+
function reasonOf(phase) {
|
|
1375
|
+
return isRefusedPhase(phase) ? phase.slice("refused:".length) : null;
|
|
1376
|
+
}
|
|
1377
|
+
function refusalPhase(reason) {
|
|
1378
|
+
if (reason === null || !isJoinRefusalReason(reason)) return "disconnected";
|
|
1379
|
+
return reason === "ended" ? "ended" : `refused:${reason}`;
|
|
1380
|
+
}
|
|
1381
|
+
function admissionPhase(admission) {
|
|
1382
|
+
switch (admission) {
|
|
1383
|
+
case "waiting_host":
|
|
1384
|
+
return "waiting:host_not_started";
|
|
1385
|
+
case "knocking":
|
|
1386
|
+
return "waiting:knocking";
|
|
1387
|
+
case "denied":
|
|
1388
|
+
return "denied";
|
|
1389
|
+
case "expired":
|
|
1390
|
+
return "knock_expired";
|
|
1391
|
+
case "withdrawn":
|
|
1392
|
+
return "left";
|
|
1393
|
+
case "ended":
|
|
1394
|
+
return "ended";
|
|
1395
|
+
case "removed":
|
|
1396
|
+
return "refused:removed";
|
|
1397
|
+
default:
|
|
1398
|
+
return null;
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
function nextPhase(from, event) {
|
|
1402
|
+
switch (event.type) {
|
|
1403
|
+
case "resolved":
|
|
1404
|
+
return from === "resolving" ? "prejoin" : null;
|
|
1405
|
+
case "unsupported":
|
|
1406
|
+
return from === "resolving" ? "unsupported" : null;
|
|
1407
|
+
case "join":
|
|
1408
|
+
return JOINABLE_FROM.has(from) ? "joining" : null;
|
|
1409
|
+
case "back_to_prejoin":
|
|
1410
|
+
return from === "left" || from === "disconnected" ? "prejoin" : null;
|
|
1411
|
+
case "retry":
|
|
1412
|
+
return isRefusedPhase(from) || from === "unsupported" ? "resolving" : null;
|
|
1413
|
+
case "admission": {
|
|
1414
|
+
if (from !== "joining" && !WAITING_PHASES.has(from)) return null;
|
|
1415
|
+
return admissionPhase(event.admission);
|
|
1416
|
+
}
|
|
1417
|
+
case "admitted":
|
|
1418
|
+
return WAITING_PHASES.has(from) ? "joining" : null;
|
|
1419
|
+
case "connected":
|
|
1420
|
+
return from === "joining" ? "in_call" : null;
|
|
1421
|
+
case "join_failed":
|
|
1422
|
+
return from === "joining" ? refusalPhase(event.reason) : null;
|
|
1423
|
+
case "exit":
|
|
1424
|
+
return from === "in_call" || from === "joining" ? event.to : null;
|
|
1425
|
+
case "leave":
|
|
1426
|
+
return from === "in_call" || from === "joining" || WAITING_PHASES.has(from) ? "left" : null;
|
|
1427
|
+
case "ended":
|
|
1428
|
+
return NOT_ENDABLE.has(from) ? null : "ended";
|
|
1429
|
+
case "ring_out":
|
|
1430
|
+
return IDLE_PHASES.has(from) || from === "prejoin" ? "ringing_out" : null;
|
|
1431
|
+
case "ring_in":
|
|
1432
|
+
return IDLE_PHASES.has(from) ? "ringing_in" : null;
|
|
1433
|
+
case "call_answered":
|
|
1434
|
+
return RINGING.has(from) ? "joining" : null;
|
|
1435
|
+
case "call_outcome":
|
|
1436
|
+
return RINGING.has(from) ? event.outcome : null;
|
|
1437
|
+
case "reset":
|
|
1438
|
+
return LIVE_PHASES.has(from) ? null : "resolving";
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
function resolveExit(input) {
|
|
1442
|
+
const { server, hint } = input;
|
|
1443
|
+
if (server === null) {
|
|
1444
|
+
return { to: "disconnected", reason: null, connection: "server_unreachable", notice: null };
|
|
1445
|
+
}
|
|
1446
|
+
const word = server?.exitReason ?? null;
|
|
1447
|
+
if (server !== void 0 && (server.sessionPhase === "ended" || server.meetingPhase === "ended" || word === "ended" || word === "time_limit")) {
|
|
1448
|
+
return { to: "ended", reason: word === "time_limit" ? "time_limit" : "ended", connection: "stable", notice: null };
|
|
1449
|
+
}
|
|
1450
|
+
if (word === "removed") return { to: "removed", reason: "removed", connection: "stable", notice: null };
|
|
1451
|
+
if (word === "displaced") return { to: "superseded", reason: "displaced", connection: "stable", notice: null };
|
|
1452
|
+
if (word === "sent_to_waiting") {
|
|
1453
|
+
return { to: "waiting:knocking", reason: "sent_to_waiting", connection: "stable", notice: "sent-to-waiting" };
|
|
1454
|
+
}
|
|
1455
|
+
if (hint === "DUPLICATE_IDENTITY") return { to: "superseded", reason: "displaced", connection: "stable", notice: null };
|
|
1456
|
+
if (hint === "PARTICIPANT_REMOVED" && word === null && server === void 0) {
|
|
1457
|
+
return { to: "removed", reason: "removed", connection: "stable", notice: null };
|
|
1458
|
+
}
|
|
1459
|
+
if (hint === "ROOM_DELETED" && server === void 0) {
|
|
1460
|
+
return { to: "ended", reason: "ended", connection: "stable", notice: null };
|
|
1461
|
+
}
|
|
1462
|
+
if (input.frozen === true) return { to: "inactive", reason: "inactive", connection: "stable", notice: null };
|
|
1463
|
+
return { to: "disconnected", reason: null, connection: "stable", notice: null };
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1294
1466
|
// src/core/types.ts
|
|
1295
1467
|
var asMeetingId = (value) => value;
|
|
1296
1468
|
var asCallId = (value) => value;
|
|
@@ -1382,6 +1554,39 @@ function createCallCenter(options) {
|
|
|
1382
1554
|
clearRing(invite.id);
|
|
1383
1555
|
incoming.delete(invite.id);
|
|
1384
1556
|
if (outgoing !== null && outgoing.id === invite.id) outgoing = invite;
|
|
1557
|
+
const held = options.store.snapshot().call;
|
|
1558
|
+
if (held !== null && held.invite.id === invite.id && held.direction === "incoming") {
|
|
1559
|
+
const outcome = invite.state === "connecting" || invite.state === "active" ? "answered_elsewhere" : invite.state === "declined" ? "reset" : "call_missed";
|
|
1560
|
+
const moved = outcome === "reset" ? options.store.dispatch({ type: "reset" }) : options.store.dispatch({ type: "call_outcome", outcome });
|
|
1561
|
+
if (moved) options.store.patch({ call: outcome === "reset" ? null : { ...held, invite } });
|
|
1562
|
+
}
|
|
1563
|
+
options.onSettled?.(invite);
|
|
1564
|
+
}
|
|
1565
|
+
function settleOutgoing(invite) {
|
|
1566
|
+
if (outgoing === null || outgoing.id !== invite.id) return;
|
|
1567
|
+
clearRing(invite.id);
|
|
1568
|
+
outgoing = invite;
|
|
1569
|
+
const store = options.store;
|
|
1570
|
+
const held = store.snapshot().call;
|
|
1571
|
+
if (held !== null && held.invite.id === invite.id) store.patch({ call: { ...held, invite } });
|
|
1572
|
+
switch (invite.state) {
|
|
1573
|
+
case "connecting":
|
|
1574
|
+
case "active":
|
|
1575
|
+
if (store.dispatch({ type: "call_answered" })) options.onAnswered?.(invite);
|
|
1576
|
+
break;
|
|
1577
|
+
case "declined":
|
|
1578
|
+
store.dispatch({ type: "call_outcome", outcome: "call_declined" });
|
|
1579
|
+
break;
|
|
1580
|
+
case "busy":
|
|
1581
|
+
store.dispatch({ type: "call_outcome", outcome: "call_busy" });
|
|
1582
|
+
break;
|
|
1583
|
+
case "missed":
|
|
1584
|
+
case "failed":
|
|
1585
|
+
store.dispatch({ type: "call_outcome", outcome: "call_missed" });
|
|
1586
|
+
break;
|
|
1587
|
+
default:
|
|
1588
|
+
break;
|
|
1589
|
+
}
|
|
1385
1590
|
options.onSettled?.(invite);
|
|
1386
1591
|
}
|
|
1387
1592
|
function ingest(invite) {
|
|
@@ -1390,7 +1595,7 @@ function createCallCenter(options) {
|
|
|
1390
1595
|
if (identity.userId === null) return;
|
|
1391
1596
|
if (invite.callerUserId === identity.userId) return;
|
|
1392
1597
|
const phase = options.store.snapshot().phase;
|
|
1393
|
-
if (phase
|
|
1598
|
+
if (isLivePhase(phase) || phase === "ringing_out") {
|
|
1394
1599
|
void repository.settleCallInvite(invite.id, "busy", null).then((settled) => {
|
|
1395
1600
|
to(settled.callerUserId).send(MEET_EVENTS.settled, settled);
|
|
1396
1601
|
}).catch((error) => {
|
|
@@ -1403,6 +1608,9 @@ function createCallCenter(options) {
|
|
|
1403
1608
|
return;
|
|
1404
1609
|
}
|
|
1405
1610
|
incoming.set(invite.id, { ...invite, state: "ringing" });
|
|
1611
|
+
if (options.store.snapshot().call === null && options.store.dispatch({ type: "ring_in" })) {
|
|
1612
|
+
options.store.patch({ call: { invite: { ...invite, state: "ringing" }, direction: "incoming" } });
|
|
1613
|
+
}
|
|
1406
1614
|
options.onIncoming?.(invite);
|
|
1407
1615
|
timeouts.set(
|
|
1408
1616
|
invite.id,
|
|
@@ -1440,6 +1648,7 @@ function createCallCenter(options) {
|
|
|
1440
1648
|
const invite = message.data;
|
|
1441
1649
|
const held = incoming.get(invite.id);
|
|
1442
1650
|
if (held !== void 0) settleLocal(invite);
|
|
1651
|
+
else if (outgoing?.id === invite.id) settleOutgoing(invite);
|
|
1443
1652
|
}
|
|
1444
1653
|
}
|
|
1445
1654
|
],
|
|
@@ -1506,6 +1715,9 @@ function createCallCenter(options) {
|
|
|
1506
1715
|
expiresAt: new Date(timers.now() + ringTimeoutMs).toISOString()
|
|
1507
1716
|
});
|
|
1508
1717
|
outgoing = invite;
|
|
1718
|
+
if (options.store.dispatch({ type: "ring_out" })) {
|
|
1719
|
+
options.store.patch({ call: { invite, direction: "outgoing" } });
|
|
1720
|
+
}
|
|
1509
1721
|
for (const callee of people) {
|
|
1510
1722
|
to(callee).send(MEET_EVENTS.ring, invite);
|
|
1511
1723
|
}
|
|
@@ -1514,8 +1726,7 @@ function createCallCenter(options) {
|
|
|
1514
1726
|
timers.setTimeout(() => {
|
|
1515
1727
|
if (outgoing?.id !== invite.id) return;
|
|
1516
1728
|
void repository.settleCallInvite(invite.id, "missed", null).then((settled) => {
|
|
1517
|
-
|
|
1518
|
-
options.onSettled?.(settled);
|
|
1729
|
+
settleOutgoing(settled);
|
|
1519
1730
|
}).catch(() => void 0);
|
|
1520
1731
|
}, ringTimeoutMs)
|
|
1521
1732
|
);
|
|
@@ -1530,7 +1741,9 @@ function createCallCenter(options) {
|
|
|
1530
1741
|
"A late accept must not resurrect a settled call. Close the ringing UI; the caller has already moved on."
|
|
1531
1742
|
);
|
|
1532
1743
|
}
|
|
1744
|
+
if (options.store.snapshot().phase === "ringing_in") options.store.dispatch({ type: "call_answered" });
|
|
1533
1745
|
const settled = await repository.settleCallInvite(id, "connecting", null);
|
|
1746
|
+
options.store.patch({ call: { invite: settled, direction: "incoming" } });
|
|
1534
1747
|
settleLocal(settled);
|
|
1535
1748
|
channel?.send(MEET_EVENTS.settled, settled);
|
|
1536
1749
|
to(settled.callerUserId).send(MEET_EVENTS.settled, { ...settled, mode });
|
|
@@ -1538,6 +1751,9 @@ function createCallCenter(options) {
|
|
|
1538
1751
|
},
|
|
1539
1752
|
async decline(id, message) {
|
|
1540
1753
|
const settled = await repository.settleCallInvite(id, "declined", message ?? null);
|
|
1754
|
+
if (options.store.snapshot().call?.invite.id === id && options.store.dispatch({ type: "reset" })) {
|
|
1755
|
+
options.store.patch({ call: null });
|
|
1756
|
+
}
|
|
1541
1757
|
settleLocal(settled);
|
|
1542
1758
|
channel?.send(MEET_EVENTS.settled, settled);
|
|
1543
1759
|
to(settled.callerUserId).send(MEET_EVENTS.settled, settled);
|
|
@@ -1547,6 +1763,9 @@ function createCallCenter(options) {
|
|
|
1547
1763
|
const settled = await repository.settleCallInvite(id, "cancelled", null);
|
|
1548
1764
|
clearRing(id);
|
|
1549
1765
|
if (outgoing?.id === id) outgoing = settled;
|
|
1766
|
+
if (options.store.snapshot().call?.invite.id === id && options.store.dispatch({ type: "reset" })) {
|
|
1767
|
+
options.store.patch({ call: null });
|
|
1768
|
+
}
|
|
1550
1769
|
for (const callee of settled.calleeUserIds) {
|
|
1551
1770
|
to(callee).send(MEET_EVENTS.cancel, settled);
|
|
1552
1771
|
}
|
|
@@ -1932,7 +2151,9 @@ var TABLES = {
|
|
|
1932
2151
|
/** Wave 1 (0.8): who a meeting was sent to, and what they answered. */
|
|
1933
2152
|
invitees: "meet_invitees",
|
|
1934
2153
|
/** Wave 1 (0.8): one occurrence of a series cancelled or moved. */
|
|
1935
|
-
occurrenceOverrides: "meet_occurrence_overrides"
|
|
2154
|
+
occurrenceOverrides: "meet_occurrence_overrides",
|
|
2155
|
+
/** S5: one row per RUN of a meeting; carries that run's note-taker state. */
|
|
2156
|
+
sessions: "meet_sessions"
|
|
1936
2157
|
};
|
|
1937
2158
|
var RPCS = {
|
|
1938
2159
|
/** Atomic: create the invite row and stamp its expiry in one statement. */
|
|
@@ -2408,6 +2629,18 @@ function createMeetRepository(options) {
|
|
|
2408
2629
|
);
|
|
2409
2630
|
}
|
|
2410
2631
|
}
|
|
2632
|
+
async function withRunNoteTaker(meeting) {
|
|
2633
|
+
const response = await db.from(TABLES.sessions).select("note_taker,started_at").eq("meeting_id", meeting.id).order("started_at", { ascending: false }).limit(1);
|
|
2634
|
+
const run = response.error === null ? (response.data ?? [])[0] : void 0;
|
|
2635
|
+
const noteTaker = run?.["note_taker"];
|
|
2636
|
+
if (typeof noteTaker !== "object" || noteTaker === null || Array.isArray(noteTaker)) {
|
|
2637
|
+
return meeting;
|
|
2638
|
+
}
|
|
2639
|
+
return {
|
|
2640
|
+
...meeting,
|
|
2641
|
+
metadata: { ...meeting.metadata ?? {}, note_taker: noteTaker }
|
|
2642
|
+
};
|
|
2643
|
+
}
|
|
2411
2644
|
return {
|
|
2412
2645
|
schema: MEET_SCHEMA,
|
|
2413
2646
|
tables: TABLES,
|
|
@@ -2646,13 +2879,13 @@ function createMeetRepository(options) {
|
|
|
2646
2879
|
"meet.meetingBySlug",
|
|
2647
2880
|
() => db.rpc(RPCS.meetingBySlug, { p_slug: slug })
|
|
2648
2881
|
);
|
|
2649
|
-
return projectMeeting(row);
|
|
2882
|
+
return withRunNoteTaker(projectMeeting(row));
|
|
2650
2883
|
},
|
|
2651
2884
|
async meeting(id) {
|
|
2652
2885
|
const response = await db.from(TABLES.meetings).select(MEETING_COLUMNS).eq("id", id).single();
|
|
2653
2886
|
if (response.error !== null) throw normalizeMeetError(response.error, "meet.meeting");
|
|
2654
2887
|
if (response.data === null) throw invalidResponse("meet.meeting", "no such meeting");
|
|
2655
|
-
return projectMeeting(response.data);
|
|
2888
|
+
return withRunNoteTaker(projectMeeting(response.data));
|
|
2656
2889
|
},
|
|
2657
2890
|
async listMeetings({ organizationId = null, limit = 25, before = null }) {
|
|
2658
2891
|
let query = db.from(TABLES.meetings).select(MEETING_COLUMNS);
|
|
@@ -3285,8 +3518,15 @@ var NO_GRANTS = {
|
|
|
3285
3518
|
canPublish: false,
|
|
3286
3519
|
canSubscribe: false
|
|
3287
3520
|
};
|
|
3521
|
+
var NO_SHARE = { state: "none", reason: null, remedy: null, at: 0 };
|
|
3288
3522
|
var EMPTY = {
|
|
3289
|
-
phase: "
|
|
3523
|
+
phase: "resolving",
|
|
3524
|
+
reason: null,
|
|
3525
|
+
phaseNotice: null,
|
|
3526
|
+
roomName: null,
|
|
3527
|
+
connection: "stable",
|
|
3528
|
+
share: NO_SHARE,
|
|
3529
|
+
call: null,
|
|
3290
3530
|
waiting: null,
|
|
3291
3531
|
meeting: null,
|
|
3292
3532
|
localIdentity: null,
|
|
@@ -3350,8 +3590,20 @@ function createMeetStore(initial = {}) {
|
|
|
3350
3590
|
return () => listeners.delete(listener);
|
|
3351
3591
|
},
|
|
3352
3592
|
patch(next) {
|
|
3593
|
+
if ("phase" in next || "reason" in next || "phaseNotice" in next) {
|
|
3594
|
+
throw new TypeError("meet store: the phase moves only through store.dispatch(event)");
|
|
3595
|
+
}
|
|
3353
3596
|
commit({ ...state, ...next });
|
|
3354
3597
|
},
|
|
3598
|
+
dispatch(event, detail) {
|
|
3599
|
+
const to = nextPhase(state.phase, event);
|
|
3600
|
+
if (to === null) return false;
|
|
3601
|
+
const reason = detail?.reason !== void 0 ? detail.reason : reasonOf(to);
|
|
3602
|
+
const phaseNotice = detail?.notice ?? null;
|
|
3603
|
+
if (to === state.phase && reason === state.reason && phaseNotice === state.phaseNotice) return true;
|
|
3604
|
+
commit({ ...state, phase: to, reason, phaseNotice });
|
|
3605
|
+
return true;
|
|
3606
|
+
},
|
|
3355
3607
|
setParticipants(participants) {
|
|
3356
3608
|
const names = learnNames(state.names, participants);
|
|
3357
3609
|
const hands = new Map(state.participants.map((p) => [p.identity, p.handRaised]));
|
|
@@ -3669,7 +3921,7 @@ function createMeetingSession(options) {
|
|
|
3669
3921
|
}
|
|
3670
3922
|
function apply(read) {
|
|
3671
3923
|
const snapshot = store.snapshot();
|
|
3672
|
-
if (snapshot.phase
|
|
3924
|
+
if (!isWaitingPhase(snapshot.phase)) return;
|
|
3673
3925
|
const admission = read.admission_state ?? null;
|
|
3674
3926
|
const ended = admission === "ended" || read.session_phase === "ended" || read.meeting_phase === "ended";
|
|
3675
3927
|
if (admission === "admitted" && !ended) {
|
|
@@ -3686,6 +3938,7 @@ function createMeetingSession(options) {
|
|
|
3686
3938
|
if (read.meeting_phase === "ended" && meeting !== null && meeting.endedAt === null) {
|
|
3687
3939
|
store.patch({ meeting: { ...meeting, endedAt: (/* @__PURE__ */ new Date()).toISOString() } });
|
|
3688
3940
|
}
|
|
3941
|
+
store.dispatch({ type: "admission", admission: "ended" }, { reason: "ended" });
|
|
3689
3942
|
return;
|
|
3690
3943
|
}
|
|
3691
3944
|
if (admission === null) return;
|
|
@@ -3697,6 +3950,7 @@ function createMeetingSession(options) {
|
|
|
3697
3950
|
pollSeconds: read.poll_seconds ?? snapshot.waiting?.pollSeconds ?? 3,
|
|
3698
3951
|
liveVersion: read.live_version ?? 0
|
|
3699
3952
|
});
|
|
3953
|
+
store.dispatch({ type: "admission", admission });
|
|
3700
3954
|
if (admission === "denied" || admission === "expired" || admission === "withdrawn" || admission === "removed") {
|
|
3701
3955
|
stopWaiting();
|
|
3702
3956
|
}
|
|
@@ -3792,7 +4046,7 @@ function createMeetingSession(options) {
|
|
|
3792
4046
|
// 🚨 PAYLOAD-FREE. Every receiver reads again; a spoofed hint only causes a read.
|
|
3793
4047
|
event: MEET_EVENTS.stateChanged,
|
|
3794
4048
|
onMessage: () => {
|
|
3795
|
-
if (store.snapshot().phase
|
|
4049
|
+
if (isWaitingPhase(store.snapshot().phase)) void readState2();
|
|
3796
4050
|
void refreshQueue();
|
|
3797
4051
|
}
|
|
3798
4052
|
}
|
|
@@ -3804,7 +4058,7 @@ function createMeetingSession(options) {
|
|
|
3804
4058
|
if (meeting === null) return;
|
|
3805
4059
|
const fresh = isGuest(identity) ? await repository.meetingBySlug(meeting.slug) : await readMeeting(meeting.id);
|
|
3806
4060
|
store.patch({ meeting: fresh, locked: fresh.locked });
|
|
3807
|
-
if (store.snapshot().phase
|
|
4061
|
+
if (isWaitingPhase(store.snapshot().phase)) void readState2();
|
|
3808
4062
|
}
|
|
3809
4063
|
});
|
|
3810
4064
|
},
|
|
@@ -3971,10 +4225,34 @@ function createMeetingSession(options) {
|
|
|
3971
4225
|
},
|
|
3972
4226
|
stopWaiting,
|
|
3973
4227
|
readState: readState2,
|
|
4228
|
+
async readExit(connection) {
|
|
4229
|
+
const meeting = store.snapshot().meeting;
|
|
4230
|
+
const pass = options.resolvePass?.() ?? null;
|
|
4231
|
+
if (meeting === null || pass === null) return void 0;
|
|
4232
|
+
try {
|
|
4233
|
+
const response = await options.api.request({
|
|
4234
|
+
path: `${MEET_ROUTES.state}?meeting_id=${encodeURIComponent(meeting.id)}&connection=${encodeURIComponent(connection)}`,
|
|
4235
|
+
method: "GET",
|
|
4236
|
+
requireAuth: false,
|
|
4237
|
+
operation: "meet.state(exit)",
|
|
4238
|
+
headers: { [MEETING_PASS_HEADER]: pass }
|
|
4239
|
+
});
|
|
4240
|
+
if (!response.ok) return null;
|
|
4241
|
+
const read = await response.json();
|
|
4242
|
+
return {
|
|
4243
|
+
exitReason: read.exit_reason ?? null,
|
|
4244
|
+
sessionPhase: read.session_phase ?? null,
|
|
4245
|
+
meetingPhase: read.meeting_phase ?? null
|
|
4246
|
+
};
|
|
4247
|
+
} catch {
|
|
4248
|
+
return null;
|
|
4249
|
+
}
|
|
4250
|
+
},
|
|
3974
4251
|
async withdraw() {
|
|
3975
4252
|
stopWaiting();
|
|
3976
4253
|
await postLeave("withdraw");
|
|
3977
4254
|
patchWaiting({ admission: "withdrawn" });
|
|
4255
|
+
store.dispatch({ type: "admission", admission: "withdrawn" });
|
|
3978
4256
|
hint();
|
|
3979
4257
|
},
|
|
3980
4258
|
async askAgain() {
|
|
@@ -4456,6 +4734,9 @@ var TRANSCRIPTION_ATTRIBUTES = {
|
|
|
4456
4734
|
};
|
|
4457
4735
|
|
|
4458
4736
|
// src/core/room.ts
|
|
4737
|
+
function SCREEN_SHARE_BLOCKED_REMEDY_FOR(remedy) {
|
|
4738
|
+
return /administrator|policy/i.test(remedy) ? remedy : SCREEN_SHARE_BLOCKED_REMEDY;
|
|
4739
|
+
}
|
|
4459
4740
|
var PARTICIPANT_ROLE_ATTRIBUTE = "matrx.participant.role";
|
|
4460
4741
|
var PARTICIPANT_CAN_RECORD_ATTRIBUTE = "matrx.participant.can_record";
|
|
4461
4742
|
var PARTICIPANT_STANDING_ATTRIBUTE = "matrx.participant.standing";
|
|
@@ -4523,7 +4804,7 @@ function createRoomEngine(options) {
|
|
|
4523
4804
|
let disposed = false;
|
|
4524
4805
|
let moving = false;
|
|
4525
4806
|
const confirmingEnds = /* @__PURE__ */ new WeakSet();
|
|
4526
|
-
async function
|
|
4807
|
+
async function dropRoom() {
|
|
4527
4808
|
const target = driver;
|
|
4528
4809
|
driver = null;
|
|
4529
4810
|
if (current !== null) {
|
|
@@ -4532,9 +4813,14 @@ function createRoomEngine(options) {
|
|
|
4532
4813
|
}
|
|
4533
4814
|
store.setLocalTrack("microphone", IDLE_TRACK);
|
|
4534
4815
|
store.setLocalTrack("camera", IDLE_TRACK);
|
|
4535
|
-
store.patch({
|
|
4816
|
+
store.patch({ share: NO_SHARE, connection: "stable" });
|
|
4536
4817
|
await target?.disconnect();
|
|
4537
4818
|
}
|
|
4819
|
+
async function leaveRoom() {
|
|
4820
|
+
store.dispatch({ type: "leave" });
|
|
4821
|
+
await dropRoom();
|
|
4822
|
+
options.onLeft?.(null);
|
|
4823
|
+
}
|
|
4538
4824
|
async function confirmMeetingEnd() {
|
|
4539
4825
|
const meeting = store.snapshot().meeting;
|
|
4540
4826
|
const target = driver;
|
|
@@ -4556,7 +4842,9 @@ function createRoomEngine(options) {
|
|
|
4556
4842
|
const latest = store.snapshot().meeting;
|
|
4557
4843
|
if (latest === null) return;
|
|
4558
4844
|
store.patch({ meeting: { ...latest, endedAt: verified.endedAt } });
|
|
4559
|
-
|
|
4845
|
+
store.dispatch({ type: "ended" }, { reason: "ended" });
|
|
4846
|
+
await dropRoom();
|
|
4847
|
+
options.onLeft?.("ended");
|
|
4560
4848
|
} catch (error) {
|
|
4561
4849
|
report("error", `Meet could not confirm or finish meeting teardown: ${String(error)}`, "Check the meeting link again; if media remains active, close this meeting tab.");
|
|
4562
4850
|
} finally {
|
|
@@ -4568,12 +4856,12 @@ function createRoomEngine(options) {
|
|
|
4568
4856
|
options.onDiagnostic?.(remedy === void 0 ? { level, message } : { level, message, remedy });
|
|
4569
4857
|
}
|
|
4570
4858
|
let ambiguousShareDenials = 0;
|
|
4571
|
-
function
|
|
4859
|
+
function failJoin(error, operation) {
|
|
4572
4860
|
const normalized = normalizeMeetError(error, operation);
|
|
4573
4861
|
store.patch({
|
|
4574
|
-
phase: "failed",
|
|
4575
4862
|
failure: { message: normalized.message, remedy: normalized.remedy, reason: normalized.reason }
|
|
4576
4863
|
});
|
|
4864
|
+
store.dispatch({ type: "join_failed", reason: normalized.reason ?? null });
|
|
4577
4865
|
report(
|
|
4578
4866
|
normalized.code === "session-unavailable" ? "warn" : "error",
|
|
4579
4867
|
normalized.message,
|
|
@@ -4581,6 +4869,14 @@ function createRoomEngine(options) {
|
|
|
4581
4869
|
);
|
|
4582
4870
|
return normalized;
|
|
4583
4871
|
}
|
|
4872
|
+
async function lostRoom(error, operation) {
|
|
4873
|
+
const normalized = normalizeMeetError(error, operation);
|
|
4874
|
+
store.patch({ failure: { message: normalized.message, remedy: normalized.remedy, reason: normalized.reason } });
|
|
4875
|
+
await dropRoom();
|
|
4876
|
+
store.dispatch({ type: "exit", to: "disconnected" });
|
|
4877
|
+
report("error", normalized.message, normalized.remedy);
|
|
4878
|
+
return normalized;
|
|
4879
|
+
}
|
|
4584
4880
|
const handlers = {
|
|
4585
4881
|
participants(list) {
|
|
4586
4882
|
const joinedAt = new Date(now()).toISOString();
|
|
@@ -4623,9 +4919,12 @@ function createRoomEngine(options) {
|
|
|
4623
4919
|
store.setQuality(asParticipantIdentity(who), value);
|
|
4624
4920
|
},
|
|
4625
4921
|
connectionState(state) {
|
|
4626
|
-
if (state === "connected")
|
|
4627
|
-
|
|
4628
|
-
|
|
4922
|
+
if (state === "connected") {
|
|
4923
|
+
if (store.snapshot().connection !== "stable") store.patch({ connection: "stable" });
|
|
4924
|
+
store.dispatch({ type: "connected" });
|
|
4925
|
+
} else if (state === "reconnecting") {
|
|
4926
|
+
store.patch({ connection: "reconnecting" });
|
|
4927
|
+
}
|
|
4629
4928
|
},
|
|
4630
4929
|
transcription(event) {
|
|
4631
4930
|
const snapshot = store.snapshot();
|
|
@@ -4752,17 +5051,48 @@ function createRoomEngine(options) {
|
|
|
4752
5051
|
}
|
|
4753
5052
|
},
|
|
4754
5053
|
disconnected(reason) {
|
|
4755
|
-
if (moving) return;
|
|
4756
|
-
|
|
4757
|
-
tokens.invalidate(current.roomName);
|
|
4758
|
-
current = null;
|
|
4759
|
-
}
|
|
4760
|
-
store.patch({ phase: "left" });
|
|
4761
|
-
options.onLeft?.(reason);
|
|
5054
|
+
if (moving || driver === null) return;
|
|
5055
|
+
void resolveExitAndApply(reason);
|
|
4762
5056
|
}
|
|
4763
5057
|
};
|
|
5058
|
+
async function resolveExitAndApply(hint) {
|
|
5059
|
+
const connection = current?.identity ?? store.snapshot().localIdentity ?? null;
|
|
5060
|
+
await dropRoom();
|
|
5061
|
+
let server;
|
|
5062
|
+
if (options.readExit === void 0 || connection === null || store.snapshot().meeting === null) {
|
|
5063
|
+
server = void 0;
|
|
5064
|
+
} else {
|
|
5065
|
+
try {
|
|
5066
|
+
server = await options.readExit(connection);
|
|
5067
|
+
} catch {
|
|
5068
|
+
server = null;
|
|
5069
|
+
}
|
|
5070
|
+
}
|
|
5071
|
+
if (disposed) return;
|
|
5072
|
+
const resolved = resolveExit({ server, hint, frozen: options.wasFrozen?.() ?? false });
|
|
5073
|
+
store.patch({ connection: resolved.connection });
|
|
5074
|
+
if (resolved.to === "waiting:knocking") {
|
|
5075
|
+
store.patch({
|
|
5076
|
+
waiting: {
|
|
5077
|
+
admission: "knocking",
|
|
5078
|
+
admittersPresent: null,
|
|
5079
|
+
reknockAllowed: true,
|
|
5080
|
+
knockExpiresAt: null,
|
|
5081
|
+
pollSeconds: store.snapshot().waiting?.pollSeconds ?? 3,
|
|
5082
|
+
liveVersion: 0
|
|
5083
|
+
}
|
|
5084
|
+
});
|
|
5085
|
+
}
|
|
5086
|
+
store.dispatch({ type: "exit", to: resolved.to }, { reason: resolved.reason, notice: resolved.notice });
|
|
5087
|
+
report(
|
|
5088
|
+
resolved.to === "disconnected" ? "warn" : "info",
|
|
5089
|
+
`meet: the room connection ended (${hint ?? "no LiveKit reason"}) \u2192 ${resolved.to}`,
|
|
5090
|
+
resolved.to === "disconnected" ? "Press Rejoin; the meeting is still going." : "The screen says what happened."
|
|
5091
|
+
);
|
|
5092
|
+
options.onLeft?.(hint);
|
|
5093
|
+
}
|
|
4764
5094
|
async function connect(request) {
|
|
4765
|
-
store.patch({
|
|
5095
|
+
store.patch({ failure: null, waiting: null, roomName: request.roomName, share: NO_SHARE, connection: "stable" });
|
|
4766
5096
|
const token = await tokens.get({
|
|
4767
5097
|
roomName: request.roomName,
|
|
4768
5098
|
identity,
|
|
@@ -4785,10 +5115,10 @@ function createRoomEngine(options) {
|
|
|
4785
5115
|
}
|
|
4786
5116
|
});
|
|
4787
5117
|
if (token.lobby || !token.canSubscribe) {
|
|
5118
|
+
const admission = token.admissionState !== void 0 && token.admissionState !== "admitted" ? token.admissionState : "knocking";
|
|
4788
5119
|
store.patch({
|
|
4789
|
-
phase: "lobby",
|
|
4790
5120
|
waiting: {
|
|
4791
|
-
admission
|
|
5121
|
+
admission,
|
|
4792
5122
|
admittersPresent: null,
|
|
4793
5123
|
reknockAllowed: true,
|
|
4794
5124
|
knockExpiresAt: null,
|
|
@@ -4796,9 +5126,10 @@ function createRoomEngine(options) {
|
|
|
4796
5126
|
liveVersion: 0
|
|
4797
5127
|
}
|
|
4798
5128
|
});
|
|
5129
|
+
store.dispatch({ type: "admission", admission });
|
|
4799
5130
|
return;
|
|
4800
5131
|
}
|
|
4801
|
-
store.patch({
|
|
5132
|
+
store.patch({ waiting: null });
|
|
4802
5133
|
const created = await options.driverFactory(handlers);
|
|
4803
5134
|
if (disposed) {
|
|
4804
5135
|
await created.disconnect();
|
|
@@ -4806,7 +5137,8 @@ function createRoomEngine(options) {
|
|
|
4806
5137
|
}
|
|
4807
5138
|
driver = created;
|
|
4808
5139
|
await created.connect(token.serverUrl, token.token);
|
|
4809
|
-
store.patch({
|
|
5140
|
+
store.patch({ failure: null, connection: "stable" });
|
|
5141
|
+
store.dispatch({ type: "connected" });
|
|
4810
5142
|
store.setLocalTrack("microphone", IDLE_TRACK);
|
|
4811
5143
|
store.setLocalTrack("camera", IDLE_TRACK);
|
|
4812
5144
|
const effects = options.effectsStorage?.load() ?? store.snapshot().effects;
|
|
@@ -4877,9 +5209,17 @@ function createRoomEngine(options) {
|
|
|
4877
5209
|
return {
|
|
4878
5210
|
join(request) {
|
|
4879
5211
|
if (joining !== null) return joining;
|
|
5212
|
+
if (store.snapshot().phase !== "joining" && !store.dispatch({ type: "join", click: true })) {
|
|
5213
|
+
report(
|
|
5214
|
+
"warn",
|
|
5215
|
+
`meet.join: cannot join from "${store.snapshot().phase}"`,
|
|
5216
|
+
"Join is offered from the pre-join, left, disconnected and replaced screens only."
|
|
5217
|
+
);
|
|
5218
|
+
return Promise.resolve();
|
|
5219
|
+
}
|
|
4880
5220
|
lastRequest = request;
|
|
4881
5221
|
joining = connect(request).catch((error) => {
|
|
4882
|
-
throw
|
|
5222
|
+
throw failJoin(error, "meet.join");
|
|
4883
5223
|
}).finally(() => {
|
|
4884
5224
|
joining = null;
|
|
4885
5225
|
});
|
|
@@ -4896,10 +5236,16 @@ function createRoomEngine(options) {
|
|
|
4896
5236
|
return;
|
|
4897
5237
|
}
|
|
4898
5238
|
if (joining !== null) return joining;
|
|
5239
|
+
const phase = store.snapshot().phase;
|
|
5240
|
+
const moved = phase === "joining" || store.dispatch({ type: "join", click: true }) || store.dispatch({ type: "admitted" });
|
|
5241
|
+
if (!moved) {
|
|
5242
|
+
report("warn", `meet.rejoin: cannot rejoin from "${phase}"`, "Rejoin is offered after leaving, a lost connection, or admission.");
|
|
5243
|
+
return;
|
|
5244
|
+
}
|
|
4899
5245
|
tokens.invalidate(request.roomName);
|
|
4900
5246
|
current = null;
|
|
4901
5247
|
joining = connect(request).catch((error) => {
|
|
4902
|
-
throw
|
|
5248
|
+
throw failJoin(error, "meet.rejoin");
|
|
4903
5249
|
}).finally(() => {
|
|
4904
5250
|
joining = null;
|
|
4905
5251
|
});
|
|
@@ -4944,11 +5290,11 @@ function createRoomEngine(options) {
|
|
|
4944
5290
|
joining = connect(lastRequest).finally(() => {
|
|
4945
5291
|
joining = null;
|
|
4946
5292
|
});
|
|
4947
|
-
await joining.catch((again) => {
|
|
4948
|
-
throw
|
|
5293
|
+
await joining.catch(async (again) => {
|
|
5294
|
+
throw await lostRoom(again, "meet.moveToBreakout");
|
|
4949
5295
|
});
|
|
4950
5296
|
} else {
|
|
4951
|
-
throw
|
|
5297
|
+
throw await lostRoom(error, "meet.moveToBreakout");
|
|
4952
5298
|
}
|
|
4953
5299
|
throw normalized;
|
|
4954
5300
|
} finally {
|
|
@@ -4956,6 +5302,9 @@ function createRoomEngine(options) {
|
|
|
4956
5302
|
}
|
|
4957
5303
|
},
|
|
4958
5304
|
leave: leaveRoom,
|
|
5305
|
+
backToPrejoin() {
|
|
5306
|
+
store.dispatch({ type: "back_to_prejoin", click: true });
|
|
5307
|
+
},
|
|
4959
5308
|
// Turning a device on mid-meeting is the SAME operation as turning it on
|
|
4960
5309
|
// during the join, so it runs the same function. A failure here used to
|
|
4961
5310
|
// stamp the room `failed` — a busy microphone would blank a live meeting.
|
|
@@ -4969,21 +5318,41 @@ function createRoomEngine(options) {
|
|
|
4969
5318
|
},
|
|
4970
5319
|
async setScreenShareEnabled(enabled) {
|
|
4971
5320
|
if (driver === null) return;
|
|
5321
|
+
if (enabled && driver.supportsScreenShare?.() === false) {
|
|
5322
|
+
store.patch({ share: { state: "refused", reason: "unsupported", remedy: null, at: now() } });
|
|
5323
|
+
report("warn", "meet: this browser cannot share a screen", "Share from a desktop browser (Chrome, Edge, Firefox or Safari).");
|
|
5324
|
+
return;
|
|
5325
|
+
}
|
|
5326
|
+
if (enabled) store.patch({ share: { state: "picking", reason: null, remedy: null, at: now() } });
|
|
4972
5327
|
try {
|
|
4973
5328
|
await driver.setScreenShareEnabled(enabled);
|
|
4974
5329
|
ambiguousShareDenials = 0;
|
|
5330
|
+
store.patch({ share: { state: enabled ? "presenting" : "none", reason: null, remedy: null, at: now() } });
|
|
4975
5331
|
} catch (error) {
|
|
4976
5332
|
const kind = classifyScreenShareError(error);
|
|
4977
5333
|
if (kind === "ambiguous") {
|
|
4978
5334
|
ambiguousShareDenials += 1;
|
|
4979
|
-
if (ambiguousShareDenials < 2)
|
|
5335
|
+
if (ambiguousShareDenials < 2) {
|
|
5336
|
+
store.patch({ share: NO_SHARE });
|
|
5337
|
+
return;
|
|
5338
|
+
}
|
|
4980
5339
|
}
|
|
5340
|
+
ambiguousShareDenials = 0;
|
|
4981
5341
|
const normalized = normalizeScreenShareError(error, "meet.setScreenShareEnabled");
|
|
4982
5342
|
report("warn", normalized.message, normalized.remedy);
|
|
4983
|
-
|
|
4984
|
-
|
|
5343
|
+
store.patch({
|
|
5344
|
+
share: {
|
|
5345
|
+
state: "refused",
|
|
5346
|
+
reason: kind === "other" ? "failed" : "blocked",
|
|
5347
|
+
remedy: kind === "other" ? normalized.remedy : SCREEN_SHARE_BLOCKED_REMEDY_FOR(normalized.remedy),
|
|
5348
|
+
at: now()
|
|
5349
|
+
}
|
|
5350
|
+
});
|
|
4985
5351
|
}
|
|
4986
5352
|
},
|
|
5353
|
+
dismissShareNotice() {
|
|
5354
|
+
if (store.snapshot().share.state === "refused") store.patch({ share: NO_SHARE });
|
|
5355
|
+
},
|
|
4987
5356
|
async raiseHand(raised) {
|
|
4988
5357
|
const local = store.snapshot().localIdentity;
|
|
4989
5358
|
if (local !== null) store.setHand(local, raised);
|
|
@@ -5485,7 +5854,8 @@ function createLiveKitDriver(handlers, options = {}) {
|
|
|
5485
5854
|
}).on(RoomEvent.Disconnected, (reason) => {
|
|
5486
5855
|
audioContainer?.remove();
|
|
5487
5856
|
audioContainer = null;
|
|
5488
|
-
|
|
5857
|
+
const named = reason === void 0 ? null : module2?.DisconnectReason?.[reason] ?? String(reason);
|
|
5858
|
+
handlers.disconnected(named);
|
|
5489
5859
|
});
|
|
5490
5860
|
try {
|
|
5491
5861
|
created.registerTextStreamHandler(TRANSCRIPTION_TOPIC, (reader, participantInfo) => {
|
|
@@ -5873,7 +6243,9 @@ function MeetRuntime(props) {
|
|
|
5873
6243
|
driverFactory: (handlers) => (driverRef.current ?? createLiveKitDriver)(handlers),
|
|
5874
6244
|
onDiagnostic: report,
|
|
5875
6245
|
effectsStorage,
|
|
5876
|
-
resolveDevice: (kind) => devicesHolder.current?.resolve(kind) ?? null
|
|
6246
|
+
resolveDevice: (kind) => devicesHolder.current?.resolve(kind) ?? null,
|
|
6247
|
+
// §3.4: on every LiveKit disconnect, ask the server what happened to this connection.
|
|
6248
|
+
readExit: (connection) => meetings.readExit(connection)
|
|
5877
6249
|
});
|
|
5878
6250
|
const meetings = createMeetingSession({
|
|
5879
6251
|
manager,
|
|
@@ -5908,17 +6280,17 @@ function MeetRuntime(props) {
|
|
|
5908
6280
|
const inRoom = createInRoomClient({ api, store, resolveRoomToken });
|
|
5909
6281
|
store.subscribe(() => {
|
|
5910
6282
|
const snapshot = store.snapshot();
|
|
5911
|
-
if (snapshot.phase
|
|
6283
|
+
if (isWaitingPhase(snapshot.phase) && snapshot.waiting !== null && (snapshot.waiting.admission === "knocking" || snapshot.waiting.admission === "waiting_host")) {
|
|
5912
6284
|
meetings.startWaiting();
|
|
5913
|
-
} else if (snapshot.phase
|
|
6285
|
+
} else if (!isWaitingPhase(snapshot.phase)) {
|
|
5914
6286
|
meetings.stopWaiting();
|
|
5915
6287
|
}
|
|
5916
6288
|
});
|
|
5917
6289
|
let chatReadFor = null;
|
|
5918
6290
|
store.subscribe(() => {
|
|
5919
6291
|
const snapshot = store.snapshot();
|
|
5920
|
-
if (snapshot.phase !== "
|
|
5921
|
-
if (snapshot.phase === "left" || snapshot.phase === "
|
|
6292
|
+
if (snapshot.phase !== "in_call" || snapshot.meeting === null) {
|
|
6293
|
+
if (snapshot.phase === "left" || snapshot.phase === "prejoin" || snapshot.phase === "resolving") chatReadFor = null;
|
|
5922
6294
|
return;
|
|
5923
6295
|
}
|
|
5924
6296
|
if (chatReadFor === snapshot.meeting.id) return;
|
|
@@ -5971,6 +6343,10 @@ function MeetRuntime(props) {
|
|
|
5971
6343
|
store,
|
|
5972
6344
|
identity,
|
|
5973
6345
|
onIncoming: (invite) => incomingRef.current?.(invite),
|
|
6346
|
+
// §3.6: my call was answered — the caller joins the call's room on the same machine.
|
|
6347
|
+
onAnswered: (invite) => {
|
|
6348
|
+
void engine.join({ roomName: invite.roomName, mode: invite.mode }).catch(() => void 0);
|
|
6349
|
+
},
|
|
5974
6350
|
onDiagnostic: report,
|
|
5975
6351
|
...props.ringTimeoutMs !== void 0 ? { ringTimeoutMs: props.ringTimeoutMs } : {}
|
|
5976
6352
|
});
|
|
@@ -6110,43 +6486,12 @@ function endedRecord(snapshot, given) {
|
|
|
6110
6486
|
function observedPhase(input) {
|
|
6111
6487
|
const { snapshot } = input;
|
|
6112
6488
|
if (snapshot === null) return "resolving";
|
|
6113
|
-
const
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
const reason = raw === "failed" ? snapshot.failure?.reason ?? null : null;
|
|
6117
|
-
if (reason !== null) return reason === "ended" ? "ended" : `refused:${reason}`;
|
|
6118
|
-
switch (raw) {
|
|
6119
|
-
case "idle":
|
|
6120
|
-
case "failed":
|
|
6121
|
-
case "left":
|
|
6122
|
-
return "prejoin";
|
|
6123
|
-
case "lobby":
|
|
6124
|
-
return waitingPhase(snapshot);
|
|
6125
|
-
case "requesting-token":
|
|
6126
|
-
case "connecting":
|
|
6127
|
-
return "joining";
|
|
6128
|
-
case "connected":
|
|
6129
|
-
case "reconnecting":
|
|
6130
|
-
return "in_call";
|
|
6131
|
-
}
|
|
6489
|
+
const phase = snapshot.phase;
|
|
6490
|
+
if (endedRecord(snapshot, input.meeting ?? null) && !isLivePhase(phase) && !isCallPhase(phase)) return "ended";
|
|
6491
|
+
return phase;
|
|
6132
6492
|
}
|
|
6133
|
-
function
|
|
6134
|
-
|
|
6135
|
-
case "waiting_host":
|
|
6136
|
-
return "waiting:host_not_started";
|
|
6137
|
-
case "denied":
|
|
6138
|
-
return "denied";
|
|
6139
|
-
case "expired":
|
|
6140
|
-
return "knock_expired";
|
|
6141
|
-
case "withdrawn":
|
|
6142
|
-
return "left";
|
|
6143
|
-
case "ended":
|
|
6144
|
-
return "ended";
|
|
6145
|
-
case "removed":
|
|
6146
|
-
return "refused:removed";
|
|
6147
|
-
default:
|
|
6148
|
-
return "waiting:knocking";
|
|
6149
|
-
}
|
|
6493
|
+
function isCallPhase(phase) {
|
|
6494
|
+
return phase.startsWith("ringing_") || phase.startsWith("call_") || phase === "answered_elsewhere";
|
|
6150
6495
|
}
|
|
6151
6496
|
var ADMITTER_ROLES = /* @__PURE__ */ new Set(["host", "cohost"]);
|
|
6152
6497
|
function observe(input) {
|
|
@@ -6159,10 +6504,10 @@ function observe(input) {
|
|
|
6159
6504
|
const deviceInPlay = phase === "joining" || inCall;
|
|
6160
6505
|
return {
|
|
6161
6506
|
phase,
|
|
6162
|
-
reason: phase
|
|
6507
|
+
reason: phase === "ended" ? snapshot?.reason ?? null : snapshot?.reason ?? reasonOf(phase),
|
|
6163
6508
|
role,
|
|
6164
|
-
connection: snapshot?.
|
|
6165
|
-
hostPresent: inCall && snapshot !== null ? snapshot.participants.some((p) => ADMITTER_ROLES.has(p.role)) : snapshot
|
|
6509
|
+
connection: snapshot?.connection ?? "stable",
|
|
6510
|
+
hostPresent: inCall && snapshot !== null ? snapshot.participants.some((p) => ADMITTER_ROLES.has(p.role)) : snapshot !== null && isWaitingPhase(snapshot.phase) ? snapshot.waiting?.admittersPresent ?? null : null,
|
|
6166
6511
|
lobbyCount: canAdmit && snapshot !== null ? snapshot.lobby.filter((entry) => entry.state === "knocking").length : 0,
|
|
6167
6512
|
recording: snapshot?.recording === "recording" || snapshot?.recording === "stopping",
|
|
6168
6513
|
audioBlocked: null,
|
|
@@ -6963,7 +7308,7 @@ function useRoom() {
|
|
|
6963
7308
|
(participant) => participant.identity === snapshot.localIdentity
|
|
6964
7309
|
) ?? null;
|
|
6965
7310
|
return {
|
|
6966
|
-
phase: snapshot?.phase ?? "
|
|
7311
|
+
phase: snapshot?.phase ?? "resolving",
|
|
6967
7312
|
participants: snapshot?.participants ?? [],
|
|
6968
7313
|
failure: snapshot?.failure ?? null,
|
|
6969
7314
|
local,
|
|
@@ -8314,7 +8659,7 @@ function useSharedFocus(panelKey) {
|
|
|
8314
8659
|
const snapshot = useMeetSnapshot();
|
|
8315
8660
|
const focus = snapshot?.collab.focus ?? null;
|
|
8316
8661
|
const mine = focus !== null && focus.panel === panelKey ? focus : null;
|
|
8317
|
-
const canMove = !isObserverRole(snapshot?.grants.role) && snapshot?.phase === "
|
|
8662
|
+
const canMove = !isObserverRole(snapshot?.grants.role) && snapshot?.phase === "in_call";
|
|
8318
8663
|
return {
|
|
8319
8664
|
section: mine?.section || null,
|
|
8320
8665
|
byName: mine?.byName || null,
|
|
@@ -8390,6 +8735,36 @@ function useCollabPanelRequest(onRequest) {
|
|
|
8390
8735
|
var MEET_REACTIONS = ["\u{1F496}", "\u{1F44D}", "\u{1F389}", "\u{1F44F}", "\u{1F602}", "\u{1F62E}", "\u{1F622}", "\u{1F914}", "\u{1F44E}"];
|
|
8391
8736
|
|
|
8392
8737
|
// src/react/facade.ts
|
|
8738
|
+
var NO_ACTIONS = {
|
|
8739
|
+
join: async () => void 0,
|
|
8740
|
+
rejoin: async () => void 0,
|
|
8741
|
+
leave: async () => void 0,
|
|
8742
|
+
backToPrejoin: () => void 0,
|
|
8743
|
+
retry: () => void 0,
|
|
8744
|
+
resolved: () => void 0,
|
|
8745
|
+
dismissShareNotice: () => void 0,
|
|
8746
|
+
dismissCall: () => void 0
|
|
8747
|
+
};
|
|
8748
|
+
function actionsFor(host) {
|
|
8749
|
+
if (host === null) return NO_ACTIONS;
|
|
8750
|
+
const { engine, store } = host;
|
|
8751
|
+
return {
|
|
8752
|
+
join: (request) => engine.join(request),
|
|
8753
|
+
rejoin: () => engine.rejoin(),
|
|
8754
|
+
leave: () => engine.leave(),
|
|
8755
|
+
backToPrejoin: () => engine.backToPrejoin(),
|
|
8756
|
+
retry: () => {
|
|
8757
|
+
store.dispatch({ type: "retry", click: true });
|
|
8758
|
+
},
|
|
8759
|
+
resolved: () => {
|
|
8760
|
+
store.dispatch({ type: "resolved" });
|
|
8761
|
+
},
|
|
8762
|
+
dismissShareNotice: () => engine.dismissShareNotice(),
|
|
8763
|
+
dismissCall: () => {
|
|
8764
|
+
if (store.dispatch({ type: "reset" })) store.patch({ call: null });
|
|
8765
|
+
}
|
|
8766
|
+
};
|
|
8767
|
+
}
|
|
8393
8768
|
function useMeetCore() {
|
|
8394
8769
|
const host = useMeetHost();
|
|
8395
8770
|
const snapshot = useMeetSnapshot();
|
|
@@ -8397,9 +8772,24 @@ function useMeetCore() {
|
|
|
8397
8772
|
const role = useRole();
|
|
8398
8773
|
const isHost = useIsHost();
|
|
8399
8774
|
const observation = useCoreObservation();
|
|
8775
|
+
const actions = (0, import_react8.useMemo)(() => actionsFor(host), [host]);
|
|
8400
8776
|
return (0, import_react8.useMemo)(
|
|
8401
|
-
() => ({
|
|
8402
|
-
|
|
8777
|
+
() => ({
|
|
8778
|
+
host,
|
|
8779
|
+
snapshot,
|
|
8780
|
+
devices,
|
|
8781
|
+
role,
|
|
8782
|
+
isHost,
|
|
8783
|
+
observation,
|
|
8784
|
+
phase: snapshot?.phase ?? "resolving",
|
|
8785
|
+
reason: snapshot?.reason ?? null,
|
|
8786
|
+
phaseNotice: snapshot?.phaseNotice ?? null,
|
|
8787
|
+
connection: snapshot?.connection ?? "stable",
|
|
8788
|
+
share: snapshot?.share ?? NO_SHARE,
|
|
8789
|
+
call: snapshot?.call ?? null,
|
|
8790
|
+
actions
|
|
8791
|
+
}),
|
|
8792
|
+
[host, snapshot, devices, role, isHost, observation, actions]
|
|
8403
8793
|
);
|
|
8404
8794
|
}
|
|
8405
8795
|
|
|
@@ -11330,11 +11720,52 @@ function MeetSkinRoom({
|
|
|
11330
11720
|
headerControls,
|
|
11331
11721
|
observe: observe2 = false
|
|
11332
11722
|
}) {
|
|
11333
|
-
const
|
|
11723
|
+
const core = useMeetCore();
|
|
11724
|
+
const { host, snapshot, isHost, phase } = core;
|
|
11334
11725
|
const elapsed = useElapsed(snapshot?.meeting?.startedAt ?? null);
|
|
11335
|
-
const phase = snapshot?.phase ?? "idle";
|
|
11336
11726
|
if (host === null) return null;
|
|
11337
|
-
|
|
11727
|
+
const screen = (() => {
|
|
11728
|
+
if (isRefusedPhase(phase)) return "refused";
|
|
11729
|
+
switch (phase) {
|
|
11730
|
+
case "resolving":
|
|
11731
|
+
return "resolving";
|
|
11732
|
+
case "prejoin":
|
|
11733
|
+
case "guest_name":
|
|
11734
|
+
return "prejoin";
|
|
11735
|
+
case "joining":
|
|
11736
|
+
case "in_call":
|
|
11737
|
+
return "room";
|
|
11738
|
+
case "waiting:host_not_started":
|
|
11739
|
+
case "waiting:knocking":
|
|
11740
|
+
case "denied":
|
|
11741
|
+
case "knock_expired":
|
|
11742
|
+
return "waiting";
|
|
11743
|
+
case "left":
|
|
11744
|
+
return snapshot?.waiting?.admission === "withdrawn" ? "waiting" : "exit";
|
|
11745
|
+
case "disconnected":
|
|
11746
|
+
case "removed":
|
|
11747
|
+
case "superseded":
|
|
11748
|
+
case "inactive":
|
|
11749
|
+
case "unsupported":
|
|
11750
|
+
case "ended":
|
|
11751
|
+
case "record":
|
|
11752
|
+
case "ringing_out":
|
|
11753
|
+
case "ringing_in":
|
|
11754
|
+
case "call_declined":
|
|
11755
|
+
case "call_missed":
|
|
11756
|
+
case "call_busy":
|
|
11757
|
+
case "answered_elsewhere":
|
|
11758
|
+
return "exit";
|
|
11759
|
+
default: {
|
|
11760
|
+
const unhandled = phase;
|
|
11761
|
+
return unhandled;
|
|
11762
|
+
}
|
|
11763
|
+
}
|
|
11764
|
+
})();
|
|
11765
|
+
if (screen === "resolving") {
|
|
11766
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mx-meet", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__empty-body", role: "status", children: "Getting the meeting ready\u2026" }) });
|
|
11767
|
+
}
|
|
11768
|
+
if (screen === "prejoin") {
|
|
11338
11769
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mx-meet", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
11339
11770
|
PreJoin,
|
|
11340
11771
|
{
|
|
@@ -11345,9 +11776,12 @@ function MeetSkinRoom({
|
|
|
11345
11776
|
}
|
|
11346
11777
|
) });
|
|
11347
11778
|
}
|
|
11348
|
-
if (
|
|
11779
|
+
if (screen === "waiting") {
|
|
11349
11780
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mx-meet mx-meet--lobby", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(WaitingRoom, { host, ...onLeave !== void 0 ? { onLeave } : {} }) });
|
|
11350
11781
|
}
|
|
11782
|
+
if (screen === "refused" || screen === "exit") {
|
|
11783
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mx-meet mx-meet--lobby", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ExitScreen, { ...onLeave !== void 0 ? { onLeave } : {} }) });
|
|
11784
|
+
}
|
|
11351
11785
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mx-meet", children: [
|
|
11352
11786
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ConsentNotice, {}),
|
|
11353
11787
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AttendanceNotice, {}),
|
|
@@ -11367,14 +11801,148 @@ function MeetSkinRoom({
|
|
|
11367
11801
|
headerControls !== void 0 && headerControls !== null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "mx-meet__header-controls", "data-meet-header-controls": "", children: headerControls }) : null,
|
|
11368
11802
|
isHost ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(HostMenu, {}) : null
|
|
11369
11803
|
] }),
|
|
11370
|
-
|
|
11804
|
+
core.connection !== "stable" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__banner", role: "status", children: "Reconnecting\u2026" }) : null,
|
|
11805
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ShareNotice, {}),
|
|
11371
11806
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Stage, {}),
|
|
11372
11807
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Captions, {}),
|
|
11373
11808
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ControlBar, { ...onLeave !== void 0 ? { onLeave } : {} })
|
|
11374
11809
|
] });
|
|
11375
11810
|
}
|
|
11811
|
+
function ShareNotice() {
|
|
11812
|
+
const { share, actions } = useMeetCore();
|
|
11813
|
+
if (share.state !== "refused") return null;
|
|
11814
|
+
const text3 = share.reason === "unsupported" ? "You can't share your screen from this browser" : share.reason === "blocked" ? "Screen sharing is blocked" : "Couldn't start sharing your screen";
|
|
11815
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "mx-meet__banner", role: "status", "data-meet-notice": "share-unavailable", children: [
|
|
11816
|
+
text3,
|
|
11817
|
+
share.remedy !== null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "mx-meet__remedy", children: share.remedy }) : null,
|
|
11818
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "mx-meet__link", onClick: actions.dismissShareNotice, children: "Dismiss" })
|
|
11819
|
+
] });
|
|
11820
|
+
}
|
|
11821
|
+
var REFUSED_TITLES = {
|
|
11822
|
+
not_found: "Check your meeting code",
|
|
11823
|
+
cancelled: "This meeting was cancelled",
|
|
11824
|
+
expired: "This meeting link has expired",
|
|
11825
|
+
too_early: "This meeting hasn't started yet",
|
|
11826
|
+
sign_in_required: "Sign in to join this meeting",
|
|
11827
|
+
wrong_account: "You're signed in with a different account",
|
|
11828
|
+
not_invited: "You aren't invited to this meeting",
|
|
11829
|
+
locked: "This meeting is locked",
|
|
11830
|
+
removed: "You can't rejoin this meeting",
|
|
11831
|
+
lobby_rejects: "You can't ask to join this meeting",
|
|
11832
|
+
meeting_full: "This meeting is full",
|
|
11833
|
+
platform_capacity: "Meetings are busy right now",
|
|
11834
|
+
verification_required: "Verify your account to join",
|
|
11835
|
+
registration_required: "Register to join this meeting"
|
|
11836
|
+
};
|
|
11837
|
+
function ExitScreen({ onLeave }) {
|
|
11838
|
+
const { phase, reason, host, snapshot, actions, call } = useMeetCore();
|
|
11839
|
+
const [busy, setBusy] = (0, import_react10.useState)(false);
|
|
11840
|
+
const failure = snapshot?.failure ?? null;
|
|
11841
|
+
const rejoin = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
11842
|
+
import_design_system.Button,
|
|
11843
|
+
{
|
|
11844
|
+
type: "button",
|
|
11845
|
+
disabled: busy,
|
|
11846
|
+
onClick: () => {
|
|
11847
|
+
setBusy(true);
|
|
11848
|
+
void actions.rejoin().catch(() => void 0).finally(() => setBusy(false));
|
|
11849
|
+
},
|
|
11850
|
+
children: "Rejoin"
|
|
11851
|
+
}
|
|
11852
|
+
);
|
|
11853
|
+
const home = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
11854
|
+
"a",
|
|
11855
|
+
{
|
|
11856
|
+
className: "mx-meet__link",
|
|
11857
|
+
href: "/",
|
|
11858
|
+
onClick: (event) => {
|
|
11859
|
+
if (call !== null) {
|
|
11860
|
+
event.preventDefault();
|
|
11861
|
+
actions.dismissCall();
|
|
11862
|
+
}
|
|
11863
|
+
if (onLeave !== void 0) {
|
|
11864
|
+
event.preventDefault();
|
|
11865
|
+
onLeave();
|
|
11866
|
+
}
|
|
11867
|
+
},
|
|
11868
|
+
children: "Go home"
|
|
11869
|
+
}
|
|
11870
|
+
);
|
|
11871
|
+
let title;
|
|
11872
|
+
let line = null;
|
|
11873
|
+
let notice = null;
|
|
11874
|
+
let actionsNode = home;
|
|
11875
|
+
if (phase.startsWith("refused:")) {
|
|
11876
|
+
const code = phase.slice("refused:".length);
|
|
11877
|
+
title = REFUSED_TITLES[code] ?? "You can't join this meeting";
|
|
11878
|
+
line = failure?.remedy ?? null;
|
|
11879
|
+
actionsNode = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
11880
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system.Button, { type: "button", variant: "outline", onClick: actions.retry, children: "Try again" }),
|
|
11881
|
+
home
|
|
11882
|
+
] });
|
|
11883
|
+
} else {
|
|
11884
|
+
switch (phase) {
|
|
11885
|
+
case "left":
|
|
11886
|
+
title = "You left the meeting";
|
|
11887
|
+
actionsNode = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
11888
|
+
rejoin,
|
|
11889
|
+
home
|
|
11890
|
+
] });
|
|
11891
|
+
break;
|
|
11892
|
+
case "disconnected":
|
|
11893
|
+
title = "You lost your connection to the meeting";
|
|
11894
|
+
line = failure?.remedy ?? "Check your internet connection, then rejoin.";
|
|
11895
|
+
notice = "disconnected";
|
|
11896
|
+
actionsNode = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
11897
|
+
rejoin,
|
|
11898
|
+
home
|
|
11899
|
+
] });
|
|
11900
|
+
break;
|
|
11901
|
+
case "removed":
|
|
11902
|
+
title = "You've been removed from the meeting";
|
|
11903
|
+
notice = "removed";
|
|
11904
|
+
break;
|
|
11905
|
+
case "superseded":
|
|
11906
|
+
title = "You joined from another tab or device";
|
|
11907
|
+
line = "This screen left the meeting so you aren't in it twice.";
|
|
11908
|
+
notice = "displaced";
|
|
11909
|
+
actionsNode = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
11910
|
+
rejoin,
|
|
11911
|
+
home
|
|
11912
|
+
] });
|
|
11913
|
+
break;
|
|
11914
|
+
case "inactive":
|
|
11915
|
+
title = "You left the meeting because this tab was inactive";
|
|
11916
|
+
actionsNode = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
11917
|
+
rejoin,
|
|
11918
|
+
home
|
|
11919
|
+
] });
|
|
11920
|
+
break;
|
|
11921
|
+
case "unsupported":
|
|
11922
|
+
title = "This browser can't join meetings";
|
|
11923
|
+
line = "Open the link in Chrome, Edge, Firefox or Safari.";
|
|
11924
|
+
break;
|
|
11925
|
+
case "ended":
|
|
11926
|
+
case "record":
|
|
11927
|
+
title = reason === "time_limit" ? "The meeting reached its time limit" : "The meeting has ended";
|
|
11928
|
+
notice = "meeting-ended";
|
|
11929
|
+
break;
|
|
11930
|
+
default:
|
|
11931
|
+
title = "The call has ended";
|
|
11932
|
+
break;
|
|
11933
|
+
}
|
|
11934
|
+
}
|
|
11935
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mx-meet__waiting", "data-meet-exit": phase, children: [
|
|
11936
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Avatar, { name: host?.identity.displayName ?? "", url: host?.identity.avatarUrl ?? null, size: 72 }),
|
|
11937
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h1", { className: "mx-meet__prejoin-title", children: title }),
|
|
11938
|
+
line !== null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__empty-body", children: line }) : null,
|
|
11939
|
+
notice !== null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { role: "status", "data-meet-notice": notice, className: "mx-meet__sr-only", children: title }) : null,
|
|
11940
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mx-meet__waiting-actions", children: actionsNode })
|
|
11941
|
+
] });
|
|
11942
|
+
}
|
|
11376
11943
|
function WaitingRoom({ host, onLeave }) {
|
|
11377
11944
|
const { waiting, withdraw, askAgain } = useWaiting();
|
|
11945
|
+
const { phaseNotice } = useMeetCore();
|
|
11378
11946
|
const [busy, setBusy] = (0, import_react10.useState)(false);
|
|
11379
11947
|
const admission = waiting?.admission ?? "knocking";
|
|
11380
11948
|
const run = (action) => () => {
|
|
@@ -11423,6 +11991,7 @@ function WaitingRoom({ host, onLeave }) {
|
|
|
11423
11991
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mx-meet__waiting", children: [
|
|
11424
11992
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Avatar, { name: host.identity.displayName, url: host.identity.avatarUrl, size: 72 }),
|
|
11425
11993
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h1", { className: "mx-meet__prejoin-title", children: title }),
|
|
11994
|
+
phaseNotice === "sent-to-waiting" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__empty-body", role: "status", "data-meet-notice": "sent-to-waiting", children: "The host moved you back to the waiting room" }) : null,
|
|
11426
11995
|
line !== null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__empty-body", role: "status", "data-meet-notice": "host-absent", children: line }) : null,
|
|
11427
11996
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mx-meet__waiting-actions", children: actions })
|
|
11428
11997
|
] });
|
|
@@ -11917,10 +12486,17 @@ function MeetingSkinRootBody({
|
|
|
11917
12486
|
host
|
|
11918
12487
|
}) {
|
|
11919
12488
|
const snapshot = useMeetSnapshot();
|
|
11920
|
-
const phase = snapshot?.phase ?? "
|
|
12489
|
+
const phase = snapshot?.phase ?? "resolving";
|
|
11921
12490
|
(0, import_react12.useEffect)(() => {
|
|
11922
12491
|
host.meetings.watch(roomName);
|
|
11923
12492
|
}, [host, roomName]);
|
|
12493
|
+
(0, import_react12.useEffect)(() => {
|
|
12494
|
+
const now = host.store.snapshot();
|
|
12495
|
+
if (now.phase !== "resolving" && now.roomName !== null && now.roomName !== roomName && now.call === null) {
|
|
12496
|
+
host.store.dispatch({ type: "reset" });
|
|
12497
|
+
}
|
|
12498
|
+
if (host.store.snapshot().phase === "resolving") host.store.dispatch({ type: "resolved" });
|
|
12499
|
+
}, [host, roomName, phase]);
|
|
11924
12500
|
(0, import_react12.useEffect)(() => {
|
|
11925
12501
|
if (given === void 0) return;
|
|
11926
12502
|
if (host.store.snapshot().meeting !== null) return;
|
|
@@ -11932,7 +12508,7 @@ function MeetingSkinRootBody({
|
|
|
11932
12508
|
host.meetings.watchMeeting(asMeetingId(watchedId));
|
|
11933
12509
|
}, [host, watchedId]);
|
|
11934
12510
|
const record = snapshot?.meeting ?? given ?? null;
|
|
11935
|
-
if (hasEnded(record) && phase
|
|
12511
|
+
if (hasEnded(record) && !isLivePhase(phase)) {
|
|
11936
12512
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MeetingRecordView, { meeting: record });
|
|
11937
12513
|
}
|
|
11938
12514
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
@@ -11949,11 +12525,49 @@ function MeetingSkinRootBody({
|
|
|
11949
12525
|
}
|
|
11950
12526
|
|
|
11951
12527
|
// src/react/calls-ui.tsx
|
|
12528
|
+
var import_react13 = require("react");
|
|
11952
12529
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
11953
12530
|
function IncomingCallHost() {
|
|
11954
12531
|
const calls = useCalls();
|
|
11955
|
-
|
|
11956
|
-
|
|
12532
|
+
const { call, phase, actions } = useMeetCore();
|
|
12533
|
+
(0, import_react13.useEffect)(() => {
|
|
12534
|
+
if (call !== null && phase === "left") actions.dismissCall();
|
|
12535
|
+
}, [call, phase, actions]);
|
|
12536
|
+
const outcome = call !== null && (phase === "call_declined" || phase === "call_missed" || phase === "call_busy" || phase === "answered_elsewhere");
|
|
12537
|
+
(0, import_react13.useEffect)(() => {
|
|
12538
|
+
if (!outcome) return void 0;
|
|
12539
|
+
const timer = setTimeout(() => actions.dismissCall(), 5e3);
|
|
12540
|
+
return () => clearTimeout(timer);
|
|
12541
|
+
}, [outcome, actions]);
|
|
12542
|
+
const inCall = call !== null && (phase === "joining" || phase === "in_call" || phase === "disconnected" || phase === "removed" || phase === "superseded");
|
|
12543
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
12544
|
+
inCall && call !== null ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "mx-meet__call-overlay", "data-meet-call": call.invite.id, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MeetRoot, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MeetSkinRoom, { roomName: call.invite.roomName, onLeave: actions.dismissCall }) }) }) : null,
|
|
12545
|
+
calls.incoming.length > 0 || call !== null && (phase === "ringing_out" || outcome) ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "mx-meet__ringing-stack", children: [
|
|
12546
|
+
call !== null && phase === "ringing_out" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(OutgoingCallCard, { invite: call.invite }) : null,
|
|
12547
|
+
outcome && call !== null ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CallOutcomeCard, { invite: call.invite }) : null,
|
|
12548
|
+
calls.incoming.map((invite) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IncomingCallCard, { invite }, invite.id))
|
|
12549
|
+
] }) : null
|
|
12550
|
+
] });
|
|
12551
|
+
}
|
|
12552
|
+
function OutgoingCallCard({ invite }) {
|
|
12553
|
+
const calls = useCalls();
|
|
12554
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("section", { className: "mx-meet__ringing", role: "status", "aria-label": "Calling", "data-meet-notice": "ringing-out", children: [
|
|
12555
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Avatar, { name: invite.callerName, url: invite.callerAvatarUrl, size: 56 }),
|
|
12556
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "mx-meet__ringing-text", children: [
|
|
12557
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: "Calling\u2026" }),
|
|
12558
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: invite.mode === "video" ? "Video call" : "Voice call" })
|
|
12559
|
+
] }),
|
|
12560
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "mx-meet__ringing-actions", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ControlButton, { label: "Cancel call", danger: true, onClick: () => void calls.cancel(invite), children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PhoneOffIcon, {}) }) })
|
|
12561
|
+
] });
|
|
12562
|
+
}
|
|
12563
|
+
function CallOutcomeCard({ invite }) {
|
|
12564
|
+
const { phase, actions, call } = useMeetCore();
|
|
12565
|
+
const outgoing = call?.direction === "outgoing";
|
|
12566
|
+
const text3 = phase === "call_declined" ? "Call declined" : phase === "call_busy" ? "They're on another call" : phase === "answered_elsewhere" ? "Answered on another device" : outgoing ? "No answer" : `Missed call from ${invite.callerName}`;
|
|
12567
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("section", { className: "mx-meet__ringing", role: "status", "aria-label": text3, "data-meet-call-outcome": phase, children: [
|
|
12568
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "mx-meet__ringing-text", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: text3 }) }),
|
|
12569
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "mx-meet__ringing-actions", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ControlButton, { label: "Close", onClick: actions.dismissCall, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PhoneOffIcon, {}) }) })
|
|
12570
|
+
] });
|
|
11957
12571
|
}
|
|
11958
12572
|
function IncomingCallCard({ invite }) {
|
|
11959
12573
|
const calls = useCalls();
|
|
@@ -12128,26 +12742,4 @@ async function pushMeetingToGoogleCalendar(api, meetingId, target) {
|
|
|
12128
12742
|
if (!response.ok) throw await refusal(response, operation);
|
|
12129
12743
|
return await response.json();
|
|
12130
12744
|
}
|
|
12131
|
-
|
|
12132
|
-
// src/core/reasons.ts
|
|
12133
|
-
var JOIN_REFUSAL_REASONS = [
|
|
12134
|
-
"not_found",
|
|
12135
|
-
"cancelled",
|
|
12136
|
-
"ended",
|
|
12137
|
-
"expired",
|
|
12138
|
-
"too_early",
|
|
12139
|
-
"sign_in_required",
|
|
12140
|
-
"wrong_account",
|
|
12141
|
-
"not_invited",
|
|
12142
|
-
"locked",
|
|
12143
|
-
"removed",
|
|
12144
|
-
"lobby_rejects",
|
|
12145
|
-
"meeting_full",
|
|
12146
|
-
"platform_capacity",
|
|
12147
|
-
"verification_required",
|
|
12148
|
-
"registration_required"
|
|
12149
|
-
];
|
|
12150
|
-
function isJoinRefusalReason(value) {
|
|
12151
|
-
return typeof value === "string" && JOIN_REFUSAL_REASONS.includes(value);
|
|
12152
|
-
}
|
|
12153
12745
|
//# sourceMappingURL=react.cjs.map
|