@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/index.cjs
CHANGED
|
@@ -46,9 +46,11 @@ __export(src_exports, {
|
|
|
46
46
|
GUEST_RECORD_ACCESS_METADATA_KEY: () => GUEST_RECORD_ACCESS_METADATA_KEY,
|
|
47
47
|
GUEST_RECORD_NOT_SHARED: () => GUEST_RECORD_NOT_SHARED,
|
|
48
48
|
IDLE_MEDIA: () => IDLE_MEDIA,
|
|
49
|
+
IDLE_PHASES: () => IDLE_PHASES,
|
|
49
50
|
IDLE_TRACK: () => IDLE_TRACK,
|
|
50
51
|
JOIN_REFUSAL_REASONS: () => JOIN_REFUSAL_REASONS,
|
|
51
52
|
LISTEN_ONLY_NOTICE: () => LISTEN_ONLY_NOTICE,
|
|
53
|
+
LIVE_PHASES: () => LIVE_PHASES,
|
|
52
54
|
MEETING_INVITE_KIND: () => MEETING_INVITE_KIND,
|
|
53
55
|
MEETING_INVITE_VERSION: () => MEETING_INVITE_VERSION,
|
|
54
56
|
MEETING_PASS_HEADER: () => MEETING_PASS_HEADER,
|
|
@@ -64,6 +66,7 @@ __export(src_exports, {
|
|
|
64
66
|
NOTE_TAKER_IDENTITY_PREFIX: () => NOTE_TAKER_IDENTITY_PREFIX,
|
|
65
67
|
NOTE_TAKER_METADATA_KEY: () => NOTE_TAKER_METADATA_KEY,
|
|
66
68
|
NO_GRANTS: () => NO_GRANTS,
|
|
69
|
+
NO_SHARE: () => NO_SHARE,
|
|
67
70
|
ORGANIZATION_HEADER: () => ORGANIZATION_HEADER,
|
|
68
71
|
PARTICIPANT_CAN_RECORD_ATTRIBUTE: () => PARTICIPANT_CAN_RECORD_ATTRIBUTE,
|
|
69
72
|
PARTICIPANT_ROLE_ATTRIBUTE: () => PARTICIPANT_ROLE_ATTRIBUTE,
|
|
@@ -77,9 +80,11 @@ __export(src_exports, {
|
|
|
77
80
|
TABLES: () => TABLES,
|
|
78
81
|
TRANSCRIPTION_ATTRIBUTES: () => TRANSCRIPTION_ATTRIBUTES,
|
|
79
82
|
TRANSCRIPTION_TOPIC: () => TRANSCRIPTION_TOPIC,
|
|
83
|
+
WAITING_PHASES: () => WAITING_PHASES,
|
|
80
84
|
absenceSentence: () => absenceSentence,
|
|
81
85
|
activeWrapUpSummary: () => activeWrapUpSummary,
|
|
82
86
|
activityAttention: () => activityAttention,
|
|
87
|
+
admissionPhase: () => admissionPhase,
|
|
83
88
|
announceMeeting: () => announceMeeting,
|
|
84
89
|
appPanelOf: () => appPanelOf,
|
|
85
90
|
applyCollabPacket: () => applyCollabPacket,
|
|
@@ -149,10 +154,13 @@ __export(src_exports, {
|
|
|
149
154
|
isJoinRefusalReason: () => isJoinRefusalReason,
|
|
150
155
|
isLinkFollower: () => isLinkFollower,
|
|
151
156
|
isListenOnly: () => isListenOnly,
|
|
157
|
+
isLivePhase: () => isLivePhase,
|
|
152
158
|
isNoteTaker: () => isNoteTaker,
|
|
153
159
|
isObserverRole: () => isObserverRole,
|
|
154
160
|
isRealName: () => isRealName,
|
|
161
|
+
isRefusedPhase: () => isRefusedPhase,
|
|
155
162
|
isRoomEventTopic: () => isRoomEventTopic,
|
|
163
|
+
isWaitingPhase: () => isWaitingPhase,
|
|
156
164
|
learnName: () => learnName,
|
|
157
165
|
learnNames: () => learnNames,
|
|
158
166
|
listenOnlyNotice: () => listenOnlyNotice,
|
|
@@ -176,6 +184,7 @@ __export(src_exports, {
|
|
|
176
184
|
mergeRecord: () => mergeRecord,
|
|
177
185
|
microphoneNoticeCode: () => microphoneNoticeCode,
|
|
178
186
|
moveToRoom: () => moveToRoom,
|
|
187
|
+
nextPhase: () => nextPhase,
|
|
179
188
|
nextTranslationBatch: () => nextTranslationBatch,
|
|
180
189
|
normalizeDeviceError: () => normalizeDeviceError,
|
|
181
190
|
normalizeMeetError: () => normalizeMeetError,
|
|
@@ -208,10 +217,13 @@ __export(src_exports, {
|
|
|
208
217
|
pushMeetingToGoogleCalendar: () => pushMeetingToGoogleCalendar,
|
|
209
218
|
readServerRefusal: () => readServerRefusal,
|
|
210
219
|
readableTranscript: () => readableTranscript,
|
|
220
|
+
reasonOf: () => reasonOf,
|
|
211
221
|
recordingLabel: () => recordingLabel,
|
|
212
222
|
recordingNotice: () => recordingNotice,
|
|
213
223
|
recordingOffsetMs: () => recordingOffsetMs,
|
|
224
|
+
refusalPhase: () => refusalPhase,
|
|
214
225
|
rememberedMeetingPass: () => rememberedMeetingPass,
|
|
226
|
+
resolveExit: () => resolveExit,
|
|
215
227
|
roleOf: () => roleOf,
|
|
216
228
|
roomTopic: () => roomTopic,
|
|
217
229
|
rootAttributes: () => rootAttributes,
|
|
@@ -1254,6 +1266,166 @@ var MEET_EVENTS = {
|
|
|
1254
1266
|
stateChanged: "mx.state.changed"
|
|
1255
1267
|
};
|
|
1256
1268
|
|
|
1269
|
+
// src/core/reasons.ts
|
|
1270
|
+
var JOIN_REFUSAL_REASONS = [
|
|
1271
|
+
"not_found",
|
|
1272
|
+
"cancelled",
|
|
1273
|
+
"ended",
|
|
1274
|
+
"expired",
|
|
1275
|
+
"too_early",
|
|
1276
|
+
"sign_in_required",
|
|
1277
|
+
"wrong_account",
|
|
1278
|
+
"not_invited",
|
|
1279
|
+
"locked",
|
|
1280
|
+
"removed",
|
|
1281
|
+
"lobby_rejects",
|
|
1282
|
+
"meeting_full",
|
|
1283
|
+
"platform_capacity",
|
|
1284
|
+
"verification_required",
|
|
1285
|
+
"registration_required"
|
|
1286
|
+
];
|
|
1287
|
+
function isJoinRefusalReason(value) {
|
|
1288
|
+
return typeof value === "string" && JOIN_REFUSAL_REASONS.includes(value);
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
// src/core/phase.ts
|
|
1292
|
+
var LIVE_PHASES = /* @__PURE__ */ new Set(["joining", "in_call"]);
|
|
1293
|
+
var WAITING_PHASES = /* @__PURE__ */ new Set([
|
|
1294
|
+
"waiting:host_not_started",
|
|
1295
|
+
"waiting:knocking",
|
|
1296
|
+
"denied",
|
|
1297
|
+
"knock_expired"
|
|
1298
|
+
]);
|
|
1299
|
+
var JOINABLE_FROM = /* @__PURE__ */ new Set([
|
|
1300
|
+
"prejoin",
|
|
1301
|
+
"left",
|
|
1302
|
+
"disconnected",
|
|
1303
|
+
"superseded",
|
|
1304
|
+
"inactive",
|
|
1305
|
+
"denied",
|
|
1306
|
+
"knock_expired"
|
|
1307
|
+
]);
|
|
1308
|
+
var NOT_ENDABLE = /* @__PURE__ */ new Set([
|
|
1309
|
+
"ended",
|
|
1310
|
+
"record",
|
|
1311
|
+
"unsupported",
|
|
1312
|
+
"ringing_out",
|
|
1313
|
+
"ringing_in",
|
|
1314
|
+
"call_declined",
|
|
1315
|
+
"call_missed",
|
|
1316
|
+
"call_busy",
|
|
1317
|
+
"answered_elsewhere"
|
|
1318
|
+
]);
|
|
1319
|
+
var RINGING = /* @__PURE__ */ new Set(["ringing_out", "ringing_in"]);
|
|
1320
|
+
var IDLE_PHASES = /* @__PURE__ */ new Set([
|
|
1321
|
+
"resolving",
|
|
1322
|
+
"left",
|
|
1323
|
+
"call_declined",
|
|
1324
|
+
"call_missed",
|
|
1325
|
+
"call_busy",
|
|
1326
|
+
"answered_elsewhere"
|
|
1327
|
+
]);
|
|
1328
|
+
function isLivePhase(phase) {
|
|
1329
|
+
return LIVE_PHASES.has(phase);
|
|
1330
|
+
}
|
|
1331
|
+
function isWaitingPhase(phase) {
|
|
1332
|
+
return WAITING_PHASES.has(phase);
|
|
1333
|
+
}
|
|
1334
|
+
function isRefusedPhase(phase) {
|
|
1335
|
+
return phase.startsWith("refused:");
|
|
1336
|
+
}
|
|
1337
|
+
function reasonOf(phase) {
|
|
1338
|
+
return isRefusedPhase(phase) ? phase.slice("refused:".length) : null;
|
|
1339
|
+
}
|
|
1340
|
+
function refusalPhase(reason) {
|
|
1341
|
+
if (reason === null || !isJoinRefusalReason(reason)) return "disconnected";
|
|
1342
|
+
return reason === "ended" ? "ended" : `refused:${reason}`;
|
|
1343
|
+
}
|
|
1344
|
+
function admissionPhase(admission) {
|
|
1345
|
+
switch (admission) {
|
|
1346
|
+
case "waiting_host":
|
|
1347
|
+
return "waiting:host_not_started";
|
|
1348
|
+
case "knocking":
|
|
1349
|
+
return "waiting:knocking";
|
|
1350
|
+
case "denied":
|
|
1351
|
+
return "denied";
|
|
1352
|
+
case "expired":
|
|
1353
|
+
return "knock_expired";
|
|
1354
|
+
case "withdrawn":
|
|
1355
|
+
return "left";
|
|
1356
|
+
case "ended":
|
|
1357
|
+
return "ended";
|
|
1358
|
+
case "removed":
|
|
1359
|
+
return "refused:removed";
|
|
1360
|
+
default:
|
|
1361
|
+
return null;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
function nextPhase(from, event) {
|
|
1365
|
+
switch (event.type) {
|
|
1366
|
+
case "resolved":
|
|
1367
|
+
return from === "resolving" ? "prejoin" : null;
|
|
1368
|
+
case "unsupported":
|
|
1369
|
+
return from === "resolving" ? "unsupported" : null;
|
|
1370
|
+
case "join":
|
|
1371
|
+
return JOINABLE_FROM.has(from) ? "joining" : null;
|
|
1372
|
+
case "back_to_prejoin":
|
|
1373
|
+
return from === "left" || from === "disconnected" ? "prejoin" : null;
|
|
1374
|
+
case "retry":
|
|
1375
|
+
return isRefusedPhase(from) || from === "unsupported" ? "resolving" : null;
|
|
1376
|
+
case "admission": {
|
|
1377
|
+
if (from !== "joining" && !WAITING_PHASES.has(from)) return null;
|
|
1378
|
+
return admissionPhase(event.admission);
|
|
1379
|
+
}
|
|
1380
|
+
case "admitted":
|
|
1381
|
+
return WAITING_PHASES.has(from) ? "joining" : null;
|
|
1382
|
+
case "connected":
|
|
1383
|
+
return from === "joining" ? "in_call" : null;
|
|
1384
|
+
case "join_failed":
|
|
1385
|
+
return from === "joining" ? refusalPhase(event.reason) : null;
|
|
1386
|
+
case "exit":
|
|
1387
|
+
return from === "in_call" || from === "joining" ? event.to : null;
|
|
1388
|
+
case "leave":
|
|
1389
|
+
return from === "in_call" || from === "joining" || WAITING_PHASES.has(from) ? "left" : null;
|
|
1390
|
+
case "ended":
|
|
1391
|
+
return NOT_ENDABLE.has(from) ? null : "ended";
|
|
1392
|
+
case "ring_out":
|
|
1393
|
+
return IDLE_PHASES.has(from) || from === "prejoin" ? "ringing_out" : null;
|
|
1394
|
+
case "ring_in":
|
|
1395
|
+
return IDLE_PHASES.has(from) ? "ringing_in" : null;
|
|
1396
|
+
case "call_answered":
|
|
1397
|
+
return RINGING.has(from) ? "joining" : null;
|
|
1398
|
+
case "call_outcome":
|
|
1399
|
+
return RINGING.has(from) ? event.outcome : null;
|
|
1400
|
+
case "reset":
|
|
1401
|
+
return LIVE_PHASES.has(from) ? null : "resolving";
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
function resolveExit(input) {
|
|
1405
|
+
const { server, hint } = input;
|
|
1406
|
+
if (server === null) {
|
|
1407
|
+
return { to: "disconnected", reason: null, connection: "server_unreachable", notice: null };
|
|
1408
|
+
}
|
|
1409
|
+
const word = server?.exitReason ?? null;
|
|
1410
|
+
if (server !== void 0 && (server.sessionPhase === "ended" || server.meetingPhase === "ended" || word === "ended" || word === "time_limit")) {
|
|
1411
|
+
return { to: "ended", reason: word === "time_limit" ? "time_limit" : "ended", connection: "stable", notice: null };
|
|
1412
|
+
}
|
|
1413
|
+
if (word === "removed") return { to: "removed", reason: "removed", connection: "stable", notice: null };
|
|
1414
|
+
if (word === "displaced") return { to: "superseded", reason: "displaced", connection: "stable", notice: null };
|
|
1415
|
+
if (word === "sent_to_waiting") {
|
|
1416
|
+
return { to: "waiting:knocking", reason: "sent_to_waiting", connection: "stable", notice: "sent-to-waiting" };
|
|
1417
|
+
}
|
|
1418
|
+
if (hint === "DUPLICATE_IDENTITY") return { to: "superseded", reason: "displaced", connection: "stable", notice: null };
|
|
1419
|
+
if (hint === "PARTICIPANT_REMOVED" && word === null && server === void 0) {
|
|
1420
|
+
return { to: "removed", reason: "removed", connection: "stable", notice: null };
|
|
1421
|
+
}
|
|
1422
|
+
if (hint === "ROOM_DELETED" && server === void 0) {
|
|
1423
|
+
return { to: "ended", reason: "ended", connection: "stable", notice: null };
|
|
1424
|
+
}
|
|
1425
|
+
if (input.frozen === true) return { to: "inactive", reason: "inactive", connection: "stable", notice: null };
|
|
1426
|
+
return { to: "disconnected", reason: null, connection: "stable", notice: null };
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1257
1429
|
// src/core/types.ts
|
|
1258
1430
|
var asMeetingId = (value) => value;
|
|
1259
1431
|
var asCallId = (value) => value;
|
|
@@ -1345,6 +1517,39 @@ function createCallCenter(options) {
|
|
|
1345
1517
|
clearRing(invite.id);
|
|
1346
1518
|
incoming.delete(invite.id);
|
|
1347
1519
|
if (outgoing !== null && outgoing.id === invite.id) outgoing = invite;
|
|
1520
|
+
const held = options.store.snapshot().call;
|
|
1521
|
+
if (held !== null && held.invite.id === invite.id && held.direction === "incoming") {
|
|
1522
|
+
const outcome = invite.state === "connecting" || invite.state === "active" ? "answered_elsewhere" : invite.state === "declined" ? "reset" : "call_missed";
|
|
1523
|
+
const moved = outcome === "reset" ? options.store.dispatch({ type: "reset" }) : options.store.dispatch({ type: "call_outcome", outcome });
|
|
1524
|
+
if (moved) options.store.patch({ call: outcome === "reset" ? null : { ...held, invite } });
|
|
1525
|
+
}
|
|
1526
|
+
options.onSettled?.(invite);
|
|
1527
|
+
}
|
|
1528
|
+
function settleOutgoing(invite) {
|
|
1529
|
+
if (outgoing === null || outgoing.id !== invite.id) return;
|
|
1530
|
+
clearRing(invite.id);
|
|
1531
|
+
outgoing = invite;
|
|
1532
|
+
const store = options.store;
|
|
1533
|
+
const held = store.snapshot().call;
|
|
1534
|
+
if (held !== null && held.invite.id === invite.id) store.patch({ call: { ...held, invite } });
|
|
1535
|
+
switch (invite.state) {
|
|
1536
|
+
case "connecting":
|
|
1537
|
+
case "active":
|
|
1538
|
+
if (store.dispatch({ type: "call_answered" })) options.onAnswered?.(invite);
|
|
1539
|
+
break;
|
|
1540
|
+
case "declined":
|
|
1541
|
+
store.dispatch({ type: "call_outcome", outcome: "call_declined" });
|
|
1542
|
+
break;
|
|
1543
|
+
case "busy":
|
|
1544
|
+
store.dispatch({ type: "call_outcome", outcome: "call_busy" });
|
|
1545
|
+
break;
|
|
1546
|
+
case "missed":
|
|
1547
|
+
case "failed":
|
|
1548
|
+
store.dispatch({ type: "call_outcome", outcome: "call_missed" });
|
|
1549
|
+
break;
|
|
1550
|
+
default:
|
|
1551
|
+
break;
|
|
1552
|
+
}
|
|
1348
1553
|
options.onSettled?.(invite);
|
|
1349
1554
|
}
|
|
1350
1555
|
function ingest(invite) {
|
|
@@ -1353,7 +1558,7 @@ function createCallCenter(options) {
|
|
|
1353
1558
|
if (identity.userId === null) return;
|
|
1354
1559
|
if (invite.callerUserId === identity.userId) return;
|
|
1355
1560
|
const phase = options.store.snapshot().phase;
|
|
1356
|
-
if (phase
|
|
1561
|
+
if (isLivePhase(phase) || phase === "ringing_out") {
|
|
1357
1562
|
void repository.settleCallInvite(invite.id, "busy", null).then((settled) => {
|
|
1358
1563
|
to(settled.callerUserId).send(MEET_EVENTS.settled, settled);
|
|
1359
1564
|
}).catch((error) => {
|
|
@@ -1366,6 +1571,9 @@ function createCallCenter(options) {
|
|
|
1366
1571
|
return;
|
|
1367
1572
|
}
|
|
1368
1573
|
incoming.set(invite.id, { ...invite, state: "ringing" });
|
|
1574
|
+
if (options.store.snapshot().call === null && options.store.dispatch({ type: "ring_in" })) {
|
|
1575
|
+
options.store.patch({ call: { invite: { ...invite, state: "ringing" }, direction: "incoming" } });
|
|
1576
|
+
}
|
|
1369
1577
|
options.onIncoming?.(invite);
|
|
1370
1578
|
timeouts.set(
|
|
1371
1579
|
invite.id,
|
|
@@ -1403,6 +1611,7 @@ function createCallCenter(options) {
|
|
|
1403
1611
|
const invite = message.data;
|
|
1404
1612
|
const held = incoming.get(invite.id);
|
|
1405
1613
|
if (held !== void 0) settleLocal(invite);
|
|
1614
|
+
else if (outgoing?.id === invite.id) settleOutgoing(invite);
|
|
1406
1615
|
}
|
|
1407
1616
|
}
|
|
1408
1617
|
],
|
|
@@ -1469,6 +1678,9 @@ function createCallCenter(options) {
|
|
|
1469
1678
|
expiresAt: new Date(timers.now() + ringTimeoutMs).toISOString()
|
|
1470
1679
|
});
|
|
1471
1680
|
outgoing = invite;
|
|
1681
|
+
if (options.store.dispatch({ type: "ring_out" })) {
|
|
1682
|
+
options.store.patch({ call: { invite, direction: "outgoing" } });
|
|
1683
|
+
}
|
|
1472
1684
|
for (const callee of people) {
|
|
1473
1685
|
to(callee).send(MEET_EVENTS.ring, invite);
|
|
1474
1686
|
}
|
|
@@ -1477,8 +1689,7 @@ function createCallCenter(options) {
|
|
|
1477
1689
|
timers.setTimeout(() => {
|
|
1478
1690
|
if (outgoing?.id !== invite.id) return;
|
|
1479
1691
|
void repository.settleCallInvite(invite.id, "missed", null).then((settled) => {
|
|
1480
|
-
|
|
1481
|
-
options.onSettled?.(settled);
|
|
1692
|
+
settleOutgoing(settled);
|
|
1482
1693
|
}).catch(() => void 0);
|
|
1483
1694
|
}, ringTimeoutMs)
|
|
1484
1695
|
);
|
|
@@ -1493,7 +1704,9 @@ function createCallCenter(options) {
|
|
|
1493
1704
|
"A late accept must not resurrect a settled call. Close the ringing UI; the caller has already moved on."
|
|
1494
1705
|
);
|
|
1495
1706
|
}
|
|
1707
|
+
if (options.store.snapshot().phase === "ringing_in") options.store.dispatch({ type: "call_answered" });
|
|
1496
1708
|
const settled = await repository.settleCallInvite(id, "connecting", null);
|
|
1709
|
+
options.store.patch({ call: { invite: settled, direction: "incoming" } });
|
|
1497
1710
|
settleLocal(settled);
|
|
1498
1711
|
channel?.send(MEET_EVENTS.settled, settled);
|
|
1499
1712
|
to(settled.callerUserId).send(MEET_EVENTS.settled, { ...settled, mode });
|
|
@@ -1501,6 +1714,9 @@ function createCallCenter(options) {
|
|
|
1501
1714
|
},
|
|
1502
1715
|
async decline(id, message) {
|
|
1503
1716
|
const settled = await repository.settleCallInvite(id, "declined", message ?? null);
|
|
1717
|
+
if (options.store.snapshot().call?.invite.id === id && options.store.dispatch({ type: "reset" })) {
|
|
1718
|
+
options.store.patch({ call: null });
|
|
1719
|
+
}
|
|
1504
1720
|
settleLocal(settled);
|
|
1505
1721
|
channel?.send(MEET_EVENTS.settled, settled);
|
|
1506
1722
|
to(settled.callerUserId).send(MEET_EVENTS.settled, settled);
|
|
@@ -1510,6 +1726,9 @@ function createCallCenter(options) {
|
|
|
1510
1726
|
const settled = await repository.settleCallInvite(id, "cancelled", null);
|
|
1511
1727
|
clearRing(id);
|
|
1512
1728
|
if (outgoing?.id === id) outgoing = settled;
|
|
1729
|
+
if (options.store.snapshot().call?.invite.id === id && options.store.dispatch({ type: "reset" })) {
|
|
1730
|
+
options.store.patch({ call: null });
|
|
1731
|
+
}
|
|
1513
1732
|
for (const callee of settled.calleeUserIds) {
|
|
1514
1733
|
to(callee).send(MEET_EVENTS.cancel, settled);
|
|
1515
1734
|
}
|
|
@@ -1541,7 +1760,9 @@ var TABLES = {
|
|
|
1541
1760
|
/** Wave 1 (0.8): who a meeting was sent to, and what they answered. */
|
|
1542
1761
|
invitees: "meet_invitees",
|
|
1543
1762
|
/** Wave 1 (0.8): one occurrence of a series cancelled or moved. */
|
|
1544
|
-
occurrenceOverrides: "meet_occurrence_overrides"
|
|
1763
|
+
occurrenceOverrides: "meet_occurrence_overrides",
|
|
1764
|
+
/** S5: one row per RUN of a meeting; carries that run's note-taker state. */
|
|
1765
|
+
sessions: "meet_sessions"
|
|
1545
1766
|
};
|
|
1546
1767
|
var RPCS = {
|
|
1547
1768
|
/** Atomic: create the invite row and stamp its expiry in one statement. */
|
|
@@ -2017,6 +2238,18 @@ function createMeetRepository(options) {
|
|
|
2017
2238
|
);
|
|
2018
2239
|
}
|
|
2019
2240
|
}
|
|
2241
|
+
async function withRunNoteTaker(meeting) {
|
|
2242
|
+
const response = await db.from(TABLES.sessions).select("note_taker,started_at").eq("meeting_id", meeting.id).order("started_at", { ascending: false }).limit(1);
|
|
2243
|
+
const run = response.error === null ? (response.data ?? [])[0] : void 0;
|
|
2244
|
+
const noteTaker = run?.["note_taker"];
|
|
2245
|
+
if (typeof noteTaker !== "object" || noteTaker === null || Array.isArray(noteTaker)) {
|
|
2246
|
+
return meeting;
|
|
2247
|
+
}
|
|
2248
|
+
return {
|
|
2249
|
+
...meeting,
|
|
2250
|
+
metadata: { ...meeting.metadata ?? {}, note_taker: noteTaker }
|
|
2251
|
+
};
|
|
2252
|
+
}
|
|
2020
2253
|
return {
|
|
2021
2254
|
schema: MEET_SCHEMA,
|
|
2022
2255
|
tables: TABLES,
|
|
@@ -2255,13 +2488,13 @@ function createMeetRepository(options) {
|
|
|
2255
2488
|
"meet.meetingBySlug",
|
|
2256
2489
|
() => db.rpc(RPCS.meetingBySlug, { p_slug: slug })
|
|
2257
2490
|
);
|
|
2258
|
-
return projectMeeting(row);
|
|
2491
|
+
return withRunNoteTaker(projectMeeting(row));
|
|
2259
2492
|
},
|
|
2260
2493
|
async meeting(id) {
|
|
2261
2494
|
const response = await db.from(TABLES.meetings).select(MEETING_COLUMNS).eq("id", id).single();
|
|
2262
2495
|
if (response.error !== null) throw normalizeMeetError(response.error, "meet.meeting");
|
|
2263
2496
|
if (response.data === null) throw invalidResponse("meet.meeting", "no such meeting");
|
|
2264
|
-
return projectMeeting(response.data);
|
|
2497
|
+
return withRunNoteTaker(projectMeeting(response.data));
|
|
2265
2498
|
},
|
|
2266
2499
|
async listMeetings({ organizationId = null, limit = 25, before = null }) {
|
|
2267
2500
|
let query = db.from(TABLES.meetings).select(MEETING_COLUMNS);
|
|
@@ -3022,8 +3255,15 @@ var NO_GRANTS = {
|
|
|
3022
3255
|
canPublish: false,
|
|
3023
3256
|
canSubscribe: false
|
|
3024
3257
|
};
|
|
3258
|
+
var NO_SHARE = { state: "none", reason: null, remedy: null, at: 0 };
|
|
3025
3259
|
var EMPTY = {
|
|
3026
|
-
phase: "
|
|
3260
|
+
phase: "resolving",
|
|
3261
|
+
reason: null,
|
|
3262
|
+
phaseNotice: null,
|
|
3263
|
+
roomName: null,
|
|
3264
|
+
connection: "stable",
|
|
3265
|
+
share: NO_SHARE,
|
|
3266
|
+
call: null,
|
|
3027
3267
|
waiting: null,
|
|
3028
3268
|
meeting: null,
|
|
3029
3269
|
localIdentity: null,
|
|
@@ -3087,8 +3327,20 @@ function createMeetStore(initial = {}) {
|
|
|
3087
3327
|
return () => listeners.delete(listener);
|
|
3088
3328
|
},
|
|
3089
3329
|
patch(next) {
|
|
3330
|
+
if ("phase" in next || "reason" in next || "phaseNotice" in next) {
|
|
3331
|
+
throw new TypeError("meet store: the phase moves only through store.dispatch(event)");
|
|
3332
|
+
}
|
|
3090
3333
|
commit({ ...state, ...next });
|
|
3091
3334
|
},
|
|
3335
|
+
dispatch(event, detail) {
|
|
3336
|
+
const to = nextPhase(state.phase, event);
|
|
3337
|
+
if (to === null) return false;
|
|
3338
|
+
const reason = detail?.reason !== void 0 ? detail.reason : reasonOf(to);
|
|
3339
|
+
const phaseNotice = detail?.notice ?? null;
|
|
3340
|
+
if (to === state.phase && reason === state.reason && phaseNotice === state.phaseNotice) return true;
|
|
3341
|
+
commit({ ...state, phase: to, reason, phaseNotice });
|
|
3342
|
+
return true;
|
|
3343
|
+
},
|
|
3092
3344
|
setParticipants(participants) {
|
|
3093
3345
|
const names = learnNames(state.names, participants);
|
|
3094
3346
|
const hands = new Map(state.participants.map((p) => [p.identity, p.handRaised]));
|
|
@@ -4082,7 +4334,8 @@ function createLiveKitDriver(handlers, options = {}) {
|
|
|
4082
4334
|
}).on(RoomEvent.Disconnected, (reason) => {
|
|
4083
4335
|
audioContainer?.remove();
|
|
4084
4336
|
audioContainer = null;
|
|
4085
|
-
|
|
4337
|
+
const named = reason === void 0 ? null : module2?.DisconnectReason?.[reason] ?? String(reason);
|
|
4338
|
+
handlers.disconnected(named);
|
|
4086
4339
|
});
|
|
4087
4340
|
try {
|
|
4088
4341
|
created.registerTextStreamHandler(TRANSCRIPTION_TOPIC, (reader, participantInfo) => {
|
|
@@ -4430,7 +4683,7 @@ function createMeetingSession(options) {
|
|
|
4430
4683
|
}
|
|
4431
4684
|
function apply(read) {
|
|
4432
4685
|
const snapshot = store.snapshot();
|
|
4433
|
-
if (snapshot.phase
|
|
4686
|
+
if (!isWaitingPhase(snapshot.phase)) return;
|
|
4434
4687
|
const admission = read.admission_state ?? null;
|
|
4435
4688
|
const ended = admission === "ended" || read.session_phase === "ended" || read.meeting_phase === "ended";
|
|
4436
4689
|
if (admission === "admitted" && !ended) {
|
|
@@ -4447,6 +4700,7 @@ function createMeetingSession(options) {
|
|
|
4447
4700
|
if (read.meeting_phase === "ended" && meeting !== null && meeting.endedAt === null) {
|
|
4448
4701
|
store.patch({ meeting: { ...meeting, endedAt: (/* @__PURE__ */ new Date()).toISOString() } });
|
|
4449
4702
|
}
|
|
4703
|
+
store.dispatch({ type: "admission", admission: "ended" }, { reason: "ended" });
|
|
4450
4704
|
return;
|
|
4451
4705
|
}
|
|
4452
4706
|
if (admission === null) return;
|
|
@@ -4458,6 +4712,7 @@ function createMeetingSession(options) {
|
|
|
4458
4712
|
pollSeconds: read.poll_seconds ?? snapshot.waiting?.pollSeconds ?? 3,
|
|
4459
4713
|
liveVersion: read.live_version ?? 0
|
|
4460
4714
|
});
|
|
4715
|
+
store.dispatch({ type: "admission", admission });
|
|
4461
4716
|
if (admission === "denied" || admission === "expired" || admission === "withdrawn" || admission === "removed") {
|
|
4462
4717
|
stopWaiting();
|
|
4463
4718
|
}
|
|
@@ -4553,7 +4808,7 @@ function createMeetingSession(options) {
|
|
|
4553
4808
|
// 🚨 PAYLOAD-FREE. Every receiver reads again; a spoofed hint only causes a read.
|
|
4554
4809
|
event: MEET_EVENTS.stateChanged,
|
|
4555
4810
|
onMessage: () => {
|
|
4556
|
-
if (store.snapshot().phase
|
|
4811
|
+
if (isWaitingPhase(store.snapshot().phase)) void readState2();
|
|
4557
4812
|
void refreshQueue();
|
|
4558
4813
|
}
|
|
4559
4814
|
}
|
|
@@ -4565,7 +4820,7 @@ function createMeetingSession(options) {
|
|
|
4565
4820
|
if (meeting === null) return;
|
|
4566
4821
|
const fresh = isGuest(identity) ? await repository.meetingBySlug(meeting.slug) : await readMeeting(meeting.id);
|
|
4567
4822
|
store.patch({ meeting: fresh, locked: fresh.locked });
|
|
4568
|
-
if (store.snapshot().phase
|
|
4823
|
+
if (isWaitingPhase(store.snapshot().phase)) void readState2();
|
|
4569
4824
|
}
|
|
4570
4825
|
});
|
|
4571
4826
|
},
|
|
@@ -4732,10 +4987,34 @@ function createMeetingSession(options) {
|
|
|
4732
4987
|
},
|
|
4733
4988
|
stopWaiting,
|
|
4734
4989
|
readState: readState2,
|
|
4990
|
+
async readExit(connection) {
|
|
4991
|
+
const meeting = store.snapshot().meeting;
|
|
4992
|
+
const pass = options.resolvePass?.() ?? null;
|
|
4993
|
+
if (meeting === null || pass === null) return void 0;
|
|
4994
|
+
try {
|
|
4995
|
+
const response = await options.api.request({
|
|
4996
|
+
path: `${MEET_ROUTES.state}?meeting_id=${encodeURIComponent(meeting.id)}&connection=${encodeURIComponent(connection)}`,
|
|
4997
|
+
method: "GET",
|
|
4998
|
+
requireAuth: false,
|
|
4999
|
+
operation: "meet.state(exit)",
|
|
5000
|
+
headers: { [MEETING_PASS_HEADER]: pass }
|
|
5001
|
+
});
|
|
5002
|
+
if (!response.ok) return null;
|
|
5003
|
+
const read = await response.json();
|
|
5004
|
+
return {
|
|
5005
|
+
exitReason: read.exit_reason ?? null,
|
|
5006
|
+
sessionPhase: read.session_phase ?? null,
|
|
5007
|
+
meetingPhase: read.meeting_phase ?? null
|
|
5008
|
+
};
|
|
5009
|
+
} catch {
|
|
5010
|
+
return null;
|
|
5011
|
+
}
|
|
5012
|
+
},
|
|
4735
5013
|
async withdraw() {
|
|
4736
5014
|
stopWaiting();
|
|
4737
5015
|
await postLeave("withdraw");
|
|
4738
5016
|
patchWaiting({ admission: "withdrawn" });
|
|
5017
|
+
store.dispatch({ type: "admission", admission: "withdrawn" });
|
|
4739
5018
|
hint();
|
|
4740
5019
|
},
|
|
4741
5020
|
async askAgain() {
|
|
@@ -5359,6 +5638,9 @@ async function pushMeetingToGoogleCalendar(api, meetingId, target) {
|
|
|
5359
5638
|
}
|
|
5360
5639
|
|
|
5361
5640
|
// src/core/room.ts
|
|
5641
|
+
function SCREEN_SHARE_BLOCKED_REMEDY_FOR(remedy) {
|
|
5642
|
+
return /administrator|policy/i.test(remedy) ? remedy : SCREEN_SHARE_BLOCKED_REMEDY;
|
|
5643
|
+
}
|
|
5362
5644
|
var PARTICIPANT_ROLE_ATTRIBUTE = "matrx.participant.role";
|
|
5363
5645
|
var PARTICIPANT_CAN_RECORD_ATTRIBUTE = "matrx.participant.can_record";
|
|
5364
5646
|
var PARTICIPANT_STANDING_ATTRIBUTE = "matrx.participant.standing";
|
|
@@ -5426,7 +5708,7 @@ function createRoomEngine(options) {
|
|
|
5426
5708
|
let disposed = false;
|
|
5427
5709
|
let moving = false;
|
|
5428
5710
|
const confirmingEnds = /* @__PURE__ */ new WeakSet();
|
|
5429
|
-
async function
|
|
5711
|
+
async function dropRoom() {
|
|
5430
5712
|
const target = driver;
|
|
5431
5713
|
driver = null;
|
|
5432
5714
|
if (current !== null) {
|
|
@@ -5435,9 +5717,14 @@ function createRoomEngine(options) {
|
|
|
5435
5717
|
}
|
|
5436
5718
|
store.setLocalTrack("microphone", IDLE_TRACK);
|
|
5437
5719
|
store.setLocalTrack("camera", IDLE_TRACK);
|
|
5438
|
-
store.patch({
|
|
5720
|
+
store.patch({ share: NO_SHARE, connection: "stable" });
|
|
5439
5721
|
await target?.disconnect();
|
|
5440
5722
|
}
|
|
5723
|
+
async function leaveRoom() {
|
|
5724
|
+
store.dispatch({ type: "leave" });
|
|
5725
|
+
await dropRoom();
|
|
5726
|
+
options.onLeft?.(null);
|
|
5727
|
+
}
|
|
5441
5728
|
async function confirmMeetingEnd() {
|
|
5442
5729
|
const meeting = store.snapshot().meeting;
|
|
5443
5730
|
const target = driver;
|
|
@@ -5459,7 +5746,9 @@ function createRoomEngine(options) {
|
|
|
5459
5746
|
const latest = store.snapshot().meeting;
|
|
5460
5747
|
if (latest === null) return;
|
|
5461
5748
|
store.patch({ meeting: { ...latest, endedAt: verified.endedAt } });
|
|
5462
|
-
|
|
5749
|
+
store.dispatch({ type: "ended" }, { reason: "ended" });
|
|
5750
|
+
await dropRoom();
|
|
5751
|
+
options.onLeft?.("ended");
|
|
5463
5752
|
} catch (error) {
|
|
5464
5753
|
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.");
|
|
5465
5754
|
} finally {
|
|
@@ -5471,12 +5760,12 @@ function createRoomEngine(options) {
|
|
|
5471
5760
|
options.onDiagnostic?.(remedy === void 0 ? { level, message } : { level, message, remedy });
|
|
5472
5761
|
}
|
|
5473
5762
|
let ambiguousShareDenials = 0;
|
|
5474
|
-
function
|
|
5763
|
+
function failJoin(error, operation) {
|
|
5475
5764
|
const normalized = normalizeMeetError(error, operation);
|
|
5476
5765
|
store.patch({
|
|
5477
|
-
phase: "failed",
|
|
5478
5766
|
failure: { message: normalized.message, remedy: normalized.remedy, reason: normalized.reason }
|
|
5479
5767
|
});
|
|
5768
|
+
store.dispatch({ type: "join_failed", reason: normalized.reason ?? null });
|
|
5480
5769
|
report(
|
|
5481
5770
|
normalized.code === "session-unavailable" ? "warn" : "error",
|
|
5482
5771
|
normalized.message,
|
|
@@ -5484,6 +5773,14 @@ function createRoomEngine(options) {
|
|
|
5484
5773
|
);
|
|
5485
5774
|
return normalized;
|
|
5486
5775
|
}
|
|
5776
|
+
async function lostRoom(error, operation) {
|
|
5777
|
+
const normalized = normalizeMeetError(error, operation);
|
|
5778
|
+
store.patch({ failure: { message: normalized.message, remedy: normalized.remedy, reason: normalized.reason } });
|
|
5779
|
+
await dropRoom();
|
|
5780
|
+
store.dispatch({ type: "exit", to: "disconnected" });
|
|
5781
|
+
report("error", normalized.message, normalized.remedy);
|
|
5782
|
+
return normalized;
|
|
5783
|
+
}
|
|
5487
5784
|
const handlers = {
|
|
5488
5785
|
participants(list) {
|
|
5489
5786
|
const joinedAt = new Date(now()).toISOString();
|
|
@@ -5526,9 +5823,12 @@ function createRoomEngine(options) {
|
|
|
5526
5823
|
store.setQuality(asParticipantIdentity(who), value);
|
|
5527
5824
|
},
|
|
5528
5825
|
connectionState(state) {
|
|
5529
|
-
if (state === "connected")
|
|
5530
|
-
|
|
5531
|
-
|
|
5826
|
+
if (state === "connected") {
|
|
5827
|
+
if (store.snapshot().connection !== "stable") store.patch({ connection: "stable" });
|
|
5828
|
+
store.dispatch({ type: "connected" });
|
|
5829
|
+
} else if (state === "reconnecting") {
|
|
5830
|
+
store.patch({ connection: "reconnecting" });
|
|
5831
|
+
}
|
|
5532
5832
|
},
|
|
5533
5833
|
transcription(event) {
|
|
5534
5834
|
const snapshot = store.snapshot();
|
|
@@ -5655,17 +5955,48 @@ function createRoomEngine(options) {
|
|
|
5655
5955
|
}
|
|
5656
5956
|
},
|
|
5657
5957
|
disconnected(reason) {
|
|
5658
|
-
if (moving) return;
|
|
5659
|
-
|
|
5660
|
-
tokens.invalidate(current.roomName);
|
|
5661
|
-
current = null;
|
|
5662
|
-
}
|
|
5663
|
-
store.patch({ phase: "left" });
|
|
5664
|
-
options.onLeft?.(reason);
|
|
5958
|
+
if (moving || driver === null) return;
|
|
5959
|
+
void resolveExitAndApply(reason);
|
|
5665
5960
|
}
|
|
5666
5961
|
};
|
|
5962
|
+
async function resolveExitAndApply(hint) {
|
|
5963
|
+
const connection = current?.identity ?? store.snapshot().localIdentity ?? null;
|
|
5964
|
+
await dropRoom();
|
|
5965
|
+
let server;
|
|
5966
|
+
if (options.readExit === void 0 || connection === null || store.snapshot().meeting === null) {
|
|
5967
|
+
server = void 0;
|
|
5968
|
+
} else {
|
|
5969
|
+
try {
|
|
5970
|
+
server = await options.readExit(connection);
|
|
5971
|
+
} catch {
|
|
5972
|
+
server = null;
|
|
5973
|
+
}
|
|
5974
|
+
}
|
|
5975
|
+
if (disposed) return;
|
|
5976
|
+
const resolved = resolveExit({ server, hint, frozen: options.wasFrozen?.() ?? false });
|
|
5977
|
+
store.patch({ connection: resolved.connection });
|
|
5978
|
+
if (resolved.to === "waiting:knocking") {
|
|
5979
|
+
store.patch({
|
|
5980
|
+
waiting: {
|
|
5981
|
+
admission: "knocking",
|
|
5982
|
+
admittersPresent: null,
|
|
5983
|
+
reknockAllowed: true,
|
|
5984
|
+
knockExpiresAt: null,
|
|
5985
|
+
pollSeconds: store.snapshot().waiting?.pollSeconds ?? 3,
|
|
5986
|
+
liveVersion: 0
|
|
5987
|
+
}
|
|
5988
|
+
});
|
|
5989
|
+
}
|
|
5990
|
+
store.dispatch({ type: "exit", to: resolved.to }, { reason: resolved.reason, notice: resolved.notice });
|
|
5991
|
+
report(
|
|
5992
|
+
resolved.to === "disconnected" ? "warn" : "info",
|
|
5993
|
+
`meet: the room connection ended (${hint ?? "no LiveKit reason"}) \u2192 ${resolved.to}`,
|
|
5994
|
+
resolved.to === "disconnected" ? "Press Rejoin; the meeting is still going." : "The screen says what happened."
|
|
5995
|
+
);
|
|
5996
|
+
options.onLeft?.(hint);
|
|
5997
|
+
}
|
|
5667
5998
|
async function connect(request) {
|
|
5668
|
-
store.patch({
|
|
5999
|
+
store.patch({ failure: null, waiting: null, roomName: request.roomName, share: NO_SHARE, connection: "stable" });
|
|
5669
6000
|
const token = await tokens.get({
|
|
5670
6001
|
roomName: request.roomName,
|
|
5671
6002
|
identity,
|
|
@@ -5688,10 +6019,10 @@ function createRoomEngine(options) {
|
|
|
5688
6019
|
}
|
|
5689
6020
|
});
|
|
5690
6021
|
if (token.lobby || !token.canSubscribe) {
|
|
6022
|
+
const admission = token.admissionState !== void 0 && token.admissionState !== "admitted" ? token.admissionState : "knocking";
|
|
5691
6023
|
store.patch({
|
|
5692
|
-
phase: "lobby",
|
|
5693
6024
|
waiting: {
|
|
5694
|
-
admission
|
|
6025
|
+
admission,
|
|
5695
6026
|
admittersPresent: null,
|
|
5696
6027
|
reknockAllowed: true,
|
|
5697
6028
|
knockExpiresAt: null,
|
|
@@ -5699,9 +6030,10 @@ function createRoomEngine(options) {
|
|
|
5699
6030
|
liveVersion: 0
|
|
5700
6031
|
}
|
|
5701
6032
|
});
|
|
6033
|
+
store.dispatch({ type: "admission", admission });
|
|
5702
6034
|
return;
|
|
5703
6035
|
}
|
|
5704
|
-
store.patch({
|
|
6036
|
+
store.patch({ waiting: null });
|
|
5705
6037
|
const created = await options.driverFactory(handlers);
|
|
5706
6038
|
if (disposed) {
|
|
5707
6039
|
await created.disconnect();
|
|
@@ -5709,7 +6041,8 @@ function createRoomEngine(options) {
|
|
|
5709
6041
|
}
|
|
5710
6042
|
driver = created;
|
|
5711
6043
|
await created.connect(token.serverUrl, token.token);
|
|
5712
|
-
store.patch({
|
|
6044
|
+
store.patch({ failure: null, connection: "stable" });
|
|
6045
|
+
store.dispatch({ type: "connected" });
|
|
5713
6046
|
store.setLocalTrack("microphone", IDLE_TRACK);
|
|
5714
6047
|
store.setLocalTrack("camera", IDLE_TRACK);
|
|
5715
6048
|
const effects = options.effectsStorage?.load() ?? store.snapshot().effects;
|
|
@@ -5780,9 +6113,17 @@ function createRoomEngine(options) {
|
|
|
5780
6113
|
return {
|
|
5781
6114
|
join(request) {
|
|
5782
6115
|
if (joining !== null) return joining;
|
|
6116
|
+
if (store.snapshot().phase !== "joining" && !store.dispatch({ type: "join", click: true })) {
|
|
6117
|
+
report(
|
|
6118
|
+
"warn",
|
|
6119
|
+
`meet.join: cannot join from "${store.snapshot().phase}"`,
|
|
6120
|
+
"Join is offered from the pre-join, left, disconnected and replaced screens only."
|
|
6121
|
+
);
|
|
6122
|
+
return Promise.resolve();
|
|
6123
|
+
}
|
|
5783
6124
|
lastRequest = request;
|
|
5784
6125
|
joining = connect(request).catch((error) => {
|
|
5785
|
-
throw
|
|
6126
|
+
throw failJoin(error, "meet.join");
|
|
5786
6127
|
}).finally(() => {
|
|
5787
6128
|
joining = null;
|
|
5788
6129
|
});
|
|
@@ -5799,10 +6140,16 @@ function createRoomEngine(options) {
|
|
|
5799
6140
|
return;
|
|
5800
6141
|
}
|
|
5801
6142
|
if (joining !== null) return joining;
|
|
6143
|
+
const phase = store.snapshot().phase;
|
|
6144
|
+
const moved = phase === "joining" || store.dispatch({ type: "join", click: true }) || store.dispatch({ type: "admitted" });
|
|
6145
|
+
if (!moved) {
|
|
6146
|
+
report("warn", `meet.rejoin: cannot rejoin from "${phase}"`, "Rejoin is offered after leaving, a lost connection, or admission.");
|
|
6147
|
+
return;
|
|
6148
|
+
}
|
|
5802
6149
|
tokens.invalidate(request.roomName);
|
|
5803
6150
|
current = null;
|
|
5804
6151
|
joining = connect(request).catch((error) => {
|
|
5805
|
-
throw
|
|
6152
|
+
throw failJoin(error, "meet.rejoin");
|
|
5806
6153
|
}).finally(() => {
|
|
5807
6154
|
joining = null;
|
|
5808
6155
|
});
|
|
@@ -5847,11 +6194,11 @@ function createRoomEngine(options) {
|
|
|
5847
6194
|
joining = connect(lastRequest).finally(() => {
|
|
5848
6195
|
joining = null;
|
|
5849
6196
|
});
|
|
5850
|
-
await joining.catch((again) => {
|
|
5851
|
-
throw
|
|
6197
|
+
await joining.catch(async (again) => {
|
|
6198
|
+
throw await lostRoom(again, "meet.moveToBreakout");
|
|
5852
6199
|
});
|
|
5853
6200
|
} else {
|
|
5854
|
-
throw
|
|
6201
|
+
throw await lostRoom(error, "meet.moveToBreakout");
|
|
5855
6202
|
}
|
|
5856
6203
|
throw normalized;
|
|
5857
6204
|
} finally {
|
|
@@ -5859,6 +6206,9 @@ function createRoomEngine(options) {
|
|
|
5859
6206
|
}
|
|
5860
6207
|
},
|
|
5861
6208
|
leave: leaveRoom,
|
|
6209
|
+
backToPrejoin() {
|
|
6210
|
+
store.dispatch({ type: "back_to_prejoin", click: true });
|
|
6211
|
+
},
|
|
5862
6212
|
// Turning a device on mid-meeting is the SAME operation as turning it on
|
|
5863
6213
|
// during the join, so it runs the same function. A failure here used to
|
|
5864
6214
|
// stamp the room `failed` — a busy microphone would blank a live meeting.
|
|
@@ -5872,21 +6222,41 @@ function createRoomEngine(options) {
|
|
|
5872
6222
|
},
|
|
5873
6223
|
async setScreenShareEnabled(enabled) {
|
|
5874
6224
|
if (driver === null) return;
|
|
6225
|
+
if (enabled && driver.supportsScreenShare?.() === false) {
|
|
6226
|
+
store.patch({ share: { state: "refused", reason: "unsupported", remedy: null, at: now() } });
|
|
6227
|
+
report("warn", "meet: this browser cannot share a screen", "Share from a desktop browser (Chrome, Edge, Firefox or Safari).");
|
|
6228
|
+
return;
|
|
6229
|
+
}
|
|
6230
|
+
if (enabled) store.patch({ share: { state: "picking", reason: null, remedy: null, at: now() } });
|
|
5875
6231
|
try {
|
|
5876
6232
|
await driver.setScreenShareEnabled(enabled);
|
|
5877
6233
|
ambiguousShareDenials = 0;
|
|
6234
|
+
store.patch({ share: { state: enabled ? "presenting" : "none", reason: null, remedy: null, at: now() } });
|
|
5878
6235
|
} catch (error) {
|
|
5879
6236
|
const kind = classifyScreenShareError(error);
|
|
5880
6237
|
if (kind === "ambiguous") {
|
|
5881
6238
|
ambiguousShareDenials += 1;
|
|
5882
|
-
if (ambiguousShareDenials < 2)
|
|
6239
|
+
if (ambiguousShareDenials < 2) {
|
|
6240
|
+
store.patch({ share: NO_SHARE });
|
|
6241
|
+
return;
|
|
6242
|
+
}
|
|
5883
6243
|
}
|
|
6244
|
+
ambiguousShareDenials = 0;
|
|
5884
6245
|
const normalized = normalizeScreenShareError(error, "meet.setScreenShareEnabled");
|
|
5885
6246
|
report("warn", normalized.message, normalized.remedy);
|
|
5886
|
-
|
|
5887
|
-
|
|
6247
|
+
store.patch({
|
|
6248
|
+
share: {
|
|
6249
|
+
state: "refused",
|
|
6250
|
+
reason: kind === "other" ? "failed" : "blocked",
|
|
6251
|
+
remedy: kind === "other" ? normalized.remedy : SCREEN_SHARE_BLOCKED_REMEDY_FOR(normalized.remedy),
|
|
6252
|
+
at: now()
|
|
6253
|
+
}
|
|
6254
|
+
});
|
|
5888
6255
|
}
|
|
5889
6256
|
},
|
|
6257
|
+
dismissShareNotice() {
|
|
6258
|
+
if (store.snapshot().share.state === "refused") store.patch({ share: NO_SHARE });
|
|
6259
|
+
},
|
|
5890
6260
|
async raiseHand(raised) {
|
|
5891
6261
|
const local = store.snapshot().localIdentity;
|
|
5892
6262
|
if (local !== null) store.setHand(local, raised);
|
|
@@ -6853,28 +7223,6 @@ function createMeetingRecordCache(options = {}) {
|
|
|
6853
7223
|
};
|
|
6854
7224
|
}
|
|
6855
7225
|
|
|
6856
|
-
// src/core/reasons.ts
|
|
6857
|
-
var JOIN_REFUSAL_REASONS = [
|
|
6858
|
-
"not_found",
|
|
6859
|
-
"cancelled",
|
|
6860
|
-
"ended",
|
|
6861
|
-
"expired",
|
|
6862
|
-
"too_early",
|
|
6863
|
-
"sign_in_required",
|
|
6864
|
-
"wrong_account",
|
|
6865
|
-
"not_invited",
|
|
6866
|
-
"locked",
|
|
6867
|
-
"removed",
|
|
6868
|
-
"lobby_rejects",
|
|
6869
|
-
"meeting_full",
|
|
6870
|
-
"platform_capacity",
|
|
6871
|
-
"verification_required",
|
|
6872
|
-
"registration_required"
|
|
6873
|
-
];
|
|
6874
|
-
function isJoinRefusalReason(value) {
|
|
6875
|
-
return typeof value === "string" && JOIN_REFUSAL_REASONS.includes(value);
|
|
6876
|
-
}
|
|
6877
|
-
|
|
6878
7226
|
// src/core/reactions.ts
|
|
6879
7227
|
var MEET_REACTIONS = ["\u{1F496}", "\u{1F44D}", "\u{1F389}", "\u{1F44F}", "\u{1F602}", "\u{1F62E}", "\u{1F622}", "\u{1F914}", "\u{1F44E}"];
|
|
6880
7228
|
|
|
@@ -6973,43 +7321,12 @@ function endedRecord(snapshot, given) {
|
|
|
6973
7321
|
function observedPhase(input) {
|
|
6974
7322
|
const { snapshot } = input;
|
|
6975
7323
|
if (snapshot === null) return "resolving";
|
|
6976
|
-
const
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
const reason = raw === "failed" ? snapshot.failure?.reason ?? null : null;
|
|
6980
|
-
if (reason !== null) return reason === "ended" ? "ended" : `refused:${reason}`;
|
|
6981
|
-
switch (raw) {
|
|
6982
|
-
case "idle":
|
|
6983
|
-
case "failed":
|
|
6984
|
-
case "left":
|
|
6985
|
-
return "prejoin";
|
|
6986
|
-
case "lobby":
|
|
6987
|
-
return waitingPhase(snapshot);
|
|
6988
|
-
case "requesting-token":
|
|
6989
|
-
case "connecting":
|
|
6990
|
-
return "joining";
|
|
6991
|
-
case "connected":
|
|
6992
|
-
case "reconnecting":
|
|
6993
|
-
return "in_call";
|
|
6994
|
-
}
|
|
7324
|
+
const phase = snapshot.phase;
|
|
7325
|
+
if (endedRecord(snapshot, input.meeting ?? null) && !isLivePhase(phase) && !isCallPhase(phase)) return "ended";
|
|
7326
|
+
return phase;
|
|
6995
7327
|
}
|
|
6996
|
-
function
|
|
6997
|
-
|
|
6998
|
-
case "waiting_host":
|
|
6999
|
-
return "waiting:host_not_started";
|
|
7000
|
-
case "denied":
|
|
7001
|
-
return "denied";
|
|
7002
|
-
case "expired":
|
|
7003
|
-
return "knock_expired";
|
|
7004
|
-
case "withdrawn":
|
|
7005
|
-
return "left";
|
|
7006
|
-
case "ended":
|
|
7007
|
-
return "ended";
|
|
7008
|
-
case "removed":
|
|
7009
|
-
return "refused:removed";
|
|
7010
|
-
default:
|
|
7011
|
-
return "waiting:knocking";
|
|
7012
|
-
}
|
|
7328
|
+
function isCallPhase(phase) {
|
|
7329
|
+
return phase.startsWith("ringing_") || phase.startsWith("call_") || phase === "answered_elsewhere";
|
|
7013
7330
|
}
|
|
7014
7331
|
var ADMITTER_ROLES = /* @__PURE__ */ new Set(["host", "cohost"]);
|
|
7015
7332
|
function observe(input) {
|
|
@@ -7022,10 +7339,10 @@ function observe(input) {
|
|
|
7022
7339
|
const deviceInPlay = phase === "joining" || inCall;
|
|
7023
7340
|
return {
|
|
7024
7341
|
phase,
|
|
7025
|
-
reason: phase
|
|
7342
|
+
reason: phase === "ended" ? snapshot?.reason ?? null : snapshot?.reason ?? reasonOf(phase),
|
|
7026
7343
|
role,
|
|
7027
|
-
connection: snapshot?.
|
|
7028
|
-
hostPresent: inCall && snapshot !== null ? snapshot.participants.some((p) => ADMITTER_ROLES.has(p.role)) : snapshot
|
|
7344
|
+
connection: snapshot?.connection ?? "stable",
|
|
7345
|
+
hostPresent: inCall && snapshot !== null ? snapshot.participants.some((p) => ADMITTER_ROLES.has(p.role)) : snapshot !== null && isWaitingPhase(snapshot.phase) ? snapshot.waiting?.admittersPresent ?? null : null,
|
|
7029
7346
|
lobbyCount: canAdmit && snapshot !== null ? snapshot.lobby.filter((entry) => entry.state === "knocking").length : 0,
|
|
7030
7347
|
recording: snapshot?.recording === "recording" || snapshot?.recording === "stopping",
|
|
7031
7348
|
audioBlocked: null,
|