@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/core.js
CHANGED
|
@@ -1014,6 +1014,166 @@ var MEET_EVENTS = {
|
|
|
1014
1014
|
stateChanged: "mx.state.changed"
|
|
1015
1015
|
};
|
|
1016
1016
|
|
|
1017
|
+
// src/core/reasons.ts
|
|
1018
|
+
var JOIN_REFUSAL_REASONS = [
|
|
1019
|
+
"not_found",
|
|
1020
|
+
"cancelled",
|
|
1021
|
+
"ended",
|
|
1022
|
+
"expired",
|
|
1023
|
+
"too_early",
|
|
1024
|
+
"sign_in_required",
|
|
1025
|
+
"wrong_account",
|
|
1026
|
+
"not_invited",
|
|
1027
|
+
"locked",
|
|
1028
|
+
"removed",
|
|
1029
|
+
"lobby_rejects",
|
|
1030
|
+
"meeting_full",
|
|
1031
|
+
"platform_capacity",
|
|
1032
|
+
"verification_required",
|
|
1033
|
+
"registration_required"
|
|
1034
|
+
];
|
|
1035
|
+
function isJoinRefusalReason(value) {
|
|
1036
|
+
return typeof value === "string" && JOIN_REFUSAL_REASONS.includes(value);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
// src/core/phase.ts
|
|
1040
|
+
var LIVE_PHASES = /* @__PURE__ */ new Set(["joining", "in_call"]);
|
|
1041
|
+
var WAITING_PHASES = /* @__PURE__ */ new Set([
|
|
1042
|
+
"waiting:host_not_started",
|
|
1043
|
+
"waiting:knocking",
|
|
1044
|
+
"denied",
|
|
1045
|
+
"knock_expired"
|
|
1046
|
+
]);
|
|
1047
|
+
var JOINABLE_FROM = /* @__PURE__ */ new Set([
|
|
1048
|
+
"prejoin",
|
|
1049
|
+
"left",
|
|
1050
|
+
"disconnected",
|
|
1051
|
+
"superseded",
|
|
1052
|
+
"inactive",
|
|
1053
|
+
"denied",
|
|
1054
|
+
"knock_expired"
|
|
1055
|
+
]);
|
|
1056
|
+
var NOT_ENDABLE = /* @__PURE__ */ new Set([
|
|
1057
|
+
"ended",
|
|
1058
|
+
"record",
|
|
1059
|
+
"unsupported",
|
|
1060
|
+
"ringing_out",
|
|
1061
|
+
"ringing_in",
|
|
1062
|
+
"call_declined",
|
|
1063
|
+
"call_missed",
|
|
1064
|
+
"call_busy",
|
|
1065
|
+
"answered_elsewhere"
|
|
1066
|
+
]);
|
|
1067
|
+
var RINGING = /* @__PURE__ */ new Set(["ringing_out", "ringing_in"]);
|
|
1068
|
+
var IDLE_PHASES = /* @__PURE__ */ new Set([
|
|
1069
|
+
"resolving",
|
|
1070
|
+
"left",
|
|
1071
|
+
"call_declined",
|
|
1072
|
+
"call_missed",
|
|
1073
|
+
"call_busy",
|
|
1074
|
+
"answered_elsewhere"
|
|
1075
|
+
]);
|
|
1076
|
+
function isLivePhase(phase) {
|
|
1077
|
+
return LIVE_PHASES.has(phase);
|
|
1078
|
+
}
|
|
1079
|
+
function isWaitingPhase(phase) {
|
|
1080
|
+
return WAITING_PHASES.has(phase);
|
|
1081
|
+
}
|
|
1082
|
+
function isRefusedPhase(phase) {
|
|
1083
|
+
return phase.startsWith("refused:");
|
|
1084
|
+
}
|
|
1085
|
+
function reasonOf(phase) {
|
|
1086
|
+
return isRefusedPhase(phase) ? phase.slice("refused:".length) : null;
|
|
1087
|
+
}
|
|
1088
|
+
function refusalPhase(reason) {
|
|
1089
|
+
if (reason === null || !isJoinRefusalReason(reason)) return "disconnected";
|
|
1090
|
+
return reason === "ended" ? "ended" : `refused:${reason}`;
|
|
1091
|
+
}
|
|
1092
|
+
function admissionPhase(admission) {
|
|
1093
|
+
switch (admission) {
|
|
1094
|
+
case "waiting_host":
|
|
1095
|
+
return "waiting:host_not_started";
|
|
1096
|
+
case "knocking":
|
|
1097
|
+
return "waiting:knocking";
|
|
1098
|
+
case "denied":
|
|
1099
|
+
return "denied";
|
|
1100
|
+
case "expired":
|
|
1101
|
+
return "knock_expired";
|
|
1102
|
+
case "withdrawn":
|
|
1103
|
+
return "left";
|
|
1104
|
+
case "ended":
|
|
1105
|
+
return "ended";
|
|
1106
|
+
case "removed":
|
|
1107
|
+
return "refused:removed";
|
|
1108
|
+
default:
|
|
1109
|
+
return null;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
function nextPhase(from, event) {
|
|
1113
|
+
switch (event.type) {
|
|
1114
|
+
case "resolved":
|
|
1115
|
+
return from === "resolving" ? "prejoin" : null;
|
|
1116
|
+
case "unsupported":
|
|
1117
|
+
return from === "resolving" ? "unsupported" : null;
|
|
1118
|
+
case "join":
|
|
1119
|
+
return JOINABLE_FROM.has(from) ? "joining" : null;
|
|
1120
|
+
case "back_to_prejoin":
|
|
1121
|
+
return from === "left" || from === "disconnected" ? "prejoin" : null;
|
|
1122
|
+
case "retry":
|
|
1123
|
+
return isRefusedPhase(from) || from === "unsupported" ? "resolving" : null;
|
|
1124
|
+
case "admission": {
|
|
1125
|
+
if (from !== "joining" && !WAITING_PHASES.has(from)) return null;
|
|
1126
|
+
return admissionPhase(event.admission);
|
|
1127
|
+
}
|
|
1128
|
+
case "admitted":
|
|
1129
|
+
return WAITING_PHASES.has(from) ? "joining" : null;
|
|
1130
|
+
case "connected":
|
|
1131
|
+
return from === "joining" ? "in_call" : null;
|
|
1132
|
+
case "join_failed":
|
|
1133
|
+
return from === "joining" ? refusalPhase(event.reason) : null;
|
|
1134
|
+
case "exit":
|
|
1135
|
+
return from === "in_call" || from === "joining" ? event.to : null;
|
|
1136
|
+
case "leave":
|
|
1137
|
+
return from === "in_call" || from === "joining" || WAITING_PHASES.has(from) ? "left" : null;
|
|
1138
|
+
case "ended":
|
|
1139
|
+
return NOT_ENDABLE.has(from) ? null : "ended";
|
|
1140
|
+
case "ring_out":
|
|
1141
|
+
return IDLE_PHASES.has(from) || from === "prejoin" ? "ringing_out" : null;
|
|
1142
|
+
case "ring_in":
|
|
1143
|
+
return IDLE_PHASES.has(from) ? "ringing_in" : null;
|
|
1144
|
+
case "call_answered":
|
|
1145
|
+
return RINGING.has(from) ? "joining" : null;
|
|
1146
|
+
case "call_outcome":
|
|
1147
|
+
return RINGING.has(from) ? event.outcome : null;
|
|
1148
|
+
case "reset":
|
|
1149
|
+
return LIVE_PHASES.has(from) ? null : "resolving";
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
function resolveExit(input) {
|
|
1153
|
+
const { server, hint } = input;
|
|
1154
|
+
if (server === null) {
|
|
1155
|
+
return { to: "disconnected", reason: null, connection: "server_unreachable", notice: null };
|
|
1156
|
+
}
|
|
1157
|
+
const word = server?.exitReason ?? null;
|
|
1158
|
+
if (server !== void 0 && (server.sessionPhase === "ended" || server.meetingPhase === "ended" || word === "ended" || word === "time_limit")) {
|
|
1159
|
+
return { to: "ended", reason: word === "time_limit" ? "time_limit" : "ended", connection: "stable", notice: null };
|
|
1160
|
+
}
|
|
1161
|
+
if (word === "removed") return { to: "removed", reason: "removed", connection: "stable", notice: null };
|
|
1162
|
+
if (word === "displaced") return { to: "superseded", reason: "displaced", connection: "stable", notice: null };
|
|
1163
|
+
if (word === "sent_to_waiting") {
|
|
1164
|
+
return { to: "waiting:knocking", reason: "sent_to_waiting", connection: "stable", notice: "sent-to-waiting" };
|
|
1165
|
+
}
|
|
1166
|
+
if (hint === "DUPLICATE_IDENTITY") return { to: "superseded", reason: "displaced", connection: "stable", notice: null };
|
|
1167
|
+
if (hint === "PARTICIPANT_REMOVED" && word === null && server === void 0) {
|
|
1168
|
+
return { to: "removed", reason: "removed", connection: "stable", notice: null };
|
|
1169
|
+
}
|
|
1170
|
+
if (hint === "ROOM_DELETED" && server === void 0) {
|
|
1171
|
+
return { to: "ended", reason: "ended", connection: "stable", notice: null };
|
|
1172
|
+
}
|
|
1173
|
+
if (input.frozen === true) return { to: "inactive", reason: "inactive", connection: "stable", notice: null };
|
|
1174
|
+
return { to: "disconnected", reason: null, connection: "stable", notice: null };
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1017
1177
|
// src/core/types.ts
|
|
1018
1178
|
var asMeetingId = (value) => value;
|
|
1019
1179
|
var asCallId = (value) => value;
|
|
@@ -1105,6 +1265,39 @@ function createCallCenter(options) {
|
|
|
1105
1265
|
clearRing(invite.id);
|
|
1106
1266
|
incoming.delete(invite.id);
|
|
1107
1267
|
if (outgoing !== null && outgoing.id === invite.id) outgoing = invite;
|
|
1268
|
+
const held = options.store.snapshot().call;
|
|
1269
|
+
if (held !== null && held.invite.id === invite.id && held.direction === "incoming") {
|
|
1270
|
+
const outcome = invite.state === "connecting" || invite.state === "active" ? "answered_elsewhere" : invite.state === "declined" ? "reset" : "call_missed";
|
|
1271
|
+
const moved = outcome === "reset" ? options.store.dispatch({ type: "reset" }) : options.store.dispatch({ type: "call_outcome", outcome });
|
|
1272
|
+
if (moved) options.store.patch({ call: outcome === "reset" ? null : { ...held, invite } });
|
|
1273
|
+
}
|
|
1274
|
+
options.onSettled?.(invite);
|
|
1275
|
+
}
|
|
1276
|
+
function settleOutgoing(invite) {
|
|
1277
|
+
if (outgoing === null || outgoing.id !== invite.id) return;
|
|
1278
|
+
clearRing(invite.id);
|
|
1279
|
+
outgoing = invite;
|
|
1280
|
+
const store = options.store;
|
|
1281
|
+
const held = store.snapshot().call;
|
|
1282
|
+
if (held !== null && held.invite.id === invite.id) store.patch({ call: { ...held, invite } });
|
|
1283
|
+
switch (invite.state) {
|
|
1284
|
+
case "connecting":
|
|
1285
|
+
case "active":
|
|
1286
|
+
if (store.dispatch({ type: "call_answered" })) options.onAnswered?.(invite);
|
|
1287
|
+
break;
|
|
1288
|
+
case "declined":
|
|
1289
|
+
store.dispatch({ type: "call_outcome", outcome: "call_declined" });
|
|
1290
|
+
break;
|
|
1291
|
+
case "busy":
|
|
1292
|
+
store.dispatch({ type: "call_outcome", outcome: "call_busy" });
|
|
1293
|
+
break;
|
|
1294
|
+
case "missed":
|
|
1295
|
+
case "failed":
|
|
1296
|
+
store.dispatch({ type: "call_outcome", outcome: "call_missed" });
|
|
1297
|
+
break;
|
|
1298
|
+
default:
|
|
1299
|
+
break;
|
|
1300
|
+
}
|
|
1108
1301
|
options.onSettled?.(invite);
|
|
1109
1302
|
}
|
|
1110
1303
|
function ingest(invite) {
|
|
@@ -1113,7 +1306,7 @@ function createCallCenter(options) {
|
|
|
1113
1306
|
if (identity.userId === null) return;
|
|
1114
1307
|
if (invite.callerUserId === identity.userId) return;
|
|
1115
1308
|
const phase = options.store.snapshot().phase;
|
|
1116
|
-
if (phase
|
|
1309
|
+
if (isLivePhase(phase) || phase === "ringing_out") {
|
|
1117
1310
|
void repository.settleCallInvite(invite.id, "busy", null).then((settled) => {
|
|
1118
1311
|
to(settled.callerUserId).send(MEET_EVENTS.settled, settled);
|
|
1119
1312
|
}).catch((error) => {
|
|
@@ -1126,6 +1319,9 @@ function createCallCenter(options) {
|
|
|
1126
1319
|
return;
|
|
1127
1320
|
}
|
|
1128
1321
|
incoming.set(invite.id, { ...invite, state: "ringing" });
|
|
1322
|
+
if (options.store.snapshot().call === null && options.store.dispatch({ type: "ring_in" })) {
|
|
1323
|
+
options.store.patch({ call: { invite: { ...invite, state: "ringing" }, direction: "incoming" } });
|
|
1324
|
+
}
|
|
1129
1325
|
options.onIncoming?.(invite);
|
|
1130
1326
|
timeouts.set(
|
|
1131
1327
|
invite.id,
|
|
@@ -1163,6 +1359,7 @@ function createCallCenter(options) {
|
|
|
1163
1359
|
const invite = message.data;
|
|
1164
1360
|
const held = incoming.get(invite.id);
|
|
1165
1361
|
if (held !== void 0) settleLocal(invite);
|
|
1362
|
+
else if (outgoing?.id === invite.id) settleOutgoing(invite);
|
|
1166
1363
|
}
|
|
1167
1364
|
}
|
|
1168
1365
|
],
|
|
@@ -1229,6 +1426,9 @@ function createCallCenter(options) {
|
|
|
1229
1426
|
expiresAt: new Date(timers.now() + ringTimeoutMs).toISOString()
|
|
1230
1427
|
});
|
|
1231
1428
|
outgoing = invite;
|
|
1429
|
+
if (options.store.dispatch({ type: "ring_out" })) {
|
|
1430
|
+
options.store.patch({ call: { invite, direction: "outgoing" } });
|
|
1431
|
+
}
|
|
1232
1432
|
for (const callee of people) {
|
|
1233
1433
|
to(callee).send(MEET_EVENTS.ring, invite);
|
|
1234
1434
|
}
|
|
@@ -1237,8 +1437,7 @@ function createCallCenter(options) {
|
|
|
1237
1437
|
timers.setTimeout(() => {
|
|
1238
1438
|
if (outgoing?.id !== invite.id) return;
|
|
1239
1439
|
void repository.settleCallInvite(invite.id, "missed", null).then((settled) => {
|
|
1240
|
-
|
|
1241
|
-
options.onSettled?.(settled);
|
|
1440
|
+
settleOutgoing(settled);
|
|
1242
1441
|
}).catch(() => void 0);
|
|
1243
1442
|
}, ringTimeoutMs)
|
|
1244
1443
|
);
|
|
@@ -1253,7 +1452,9 @@ function createCallCenter(options) {
|
|
|
1253
1452
|
"A late accept must not resurrect a settled call. Close the ringing UI; the caller has already moved on."
|
|
1254
1453
|
);
|
|
1255
1454
|
}
|
|
1455
|
+
if (options.store.snapshot().phase === "ringing_in") options.store.dispatch({ type: "call_answered" });
|
|
1256
1456
|
const settled = await repository.settleCallInvite(id, "connecting", null);
|
|
1457
|
+
options.store.patch({ call: { invite: settled, direction: "incoming" } });
|
|
1257
1458
|
settleLocal(settled);
|
|
1258
1459
|
channel?.send(MEET_EVENTS.settled, settled);
|
|
1259
1460
|
to(settled.callerUserId).send(MEET_EVENTS.settled, { ...settled, mode });
|
|
@@ -1261,6 +1462,9 @@ function createCallCenter(options) {
|
|
|
1261
1462
|
},
|
|
1262
1463
|
async decline(id, message) {
|
|
1263
1464
|
const settled = await repository.settleCallInvite(id, "declined", message ?? null);
|
|
1465
|
+
if (options.store.snapshot().call?.invite.id === id && options.store.dispatch({ type: "reset" })) {
|
|
1466
|
+
options.store.patch({ call: null });
|
|
1467
|
+
}
|
|
1264
1468
|
settleLocal(settled);
|
|
1265
1469
|
channel?.send(MEET_EVENTS.settled, settled);
|
|
1266
1470
|
to(settled.callerUserId).send(MEET_EVENTS.settled, settled);
|
|
@@ -1270,6 +1474,9 @@ function createCallCenter(options) {
|
|
|
1270
1474
|
const settled = await repository.settleCallInvite(id, "cancelled", null);
|
|
1271
1475
|
clearRing(id);
|
|
1272
1476
|
if (outgoing?.id === id) outgoing = settled;
|
|
1477
|
+
if (options.store.snapshot().call?.invite.id === id && options.store.dispatch({ type: "reset" })) {
|
|
1478
|
+
options.store.patch({ call: null });
|
|
1479
|
+
}
|
|
1273
1480
|
for (const callee of settled.calleeUserIds) {
|
|
1274
1481
|
to(callee).send(MEET_EVENTS.cancel, settled);
|
|
1275
1482
|
}
|
|
@@ -1301,7 +1508,9 @@ var TABLES = {
|
|
|
1301
1508
|
/** Wave 1 (0.8): who a meeting was sent to, and what they answered. */
|
|
1302
1509
|
invitees: "meet_invitees",
|
|
1303
1510
|
/** Wave 1 (0.8): one occurrence of a series cancelled or moved. */
|
|
1304
|
-
occurrenceOverrides: "meet_occurrence_overrides"
|
|
1511
|
+
occurrenceOverrides: "meet_occurrence_overrides",
|
|
1512
|
+
/** S5: one row per RUN of a meeting; carries that run's note-taker state. */
|
|
1513
|
+
sessions: "meet_sessions"
|
|
1305
1514
|
};
|
|
1306
1515
|
var RPCS = {
|
|
1307
1516
|
/** Atomic: create the invite row and stamp its expiry in one statement. */
|
|
@@ -1777,6 +1986,18 @@ function createMeetRepository(options) {
|
|
|
1777
1986
|
);
|
|
1778
1987
|
}
|
|
1779
1988
|
}
|
|
1989
|
+
async function withRunNoteTaker(meeting) {
|
|
1990
|
+
const response = await db.from(TABLES.sessions).select("note_taker,started_at").eq("meeting_id", meeting.id).order("started_at", { ascending: false }).limit(1);
|
|
1991
|
+
const run = response.error === null ? (response.data ?? [])[0] : void 0;
|
|
1992
|
+
const noteTaker = run?.["note_taker"];
|
|
1993
|
+
if (typeof noteTaker !== "object" || noteTaker === null || Array.isArray(noteTaker)) {
|
|
1994
|
+
return meeting;
|
|
1995
|
+
}
|
|
1996
|
+
return {
|
|
1997
|
+
...meeting,
|
|
1998
|
+
metadata: { ...meeting.metadata ?? {}, note_taker: noteTaker }
|
|
1999
|
+
};
|
|
2000
|
+
}
|
|
1780
2001
|
return {
|
|
1781
2002
|
schema: MEET_SCHEMA,
|
|
1782
2003
|
tables: TABLES,
|
|
@@ -2015,13 +2236,13 @@ function createMeetRepository(options) {
|
|
|
2015
2236
|
"meet.meetingBySlug",
|
|
2016
2237
|
() => db.rpc(RPCS.meetingBySlug, { p_slug: slug })
|
|
2017
2238
|
);
|
|
2018
|
-
return projectMeeting(row);
|
|
2239
|
+
return withRunNoteTaker(projectMeeting(row));
|
|
2019
2240
|
},
|
|
2020
2241
|
async meeting(id) {
|
|
2021
2242
|
const response = await db.from(TABLES.meetings).select(MEETING_COLUMNS).eq("id", id).single();
|
|
2022
2243
|
if (response.error !== null) throw normalizeMeetError(response.error, "meet.meeting");
|
|
2023
2244
|
if (response.data === null) throw invalidResponse("meet.meeting", "no such meeting");
|
|
2024
|
-
return projectMeeting(response.data);
|
|
2245
|
+
return withRunNoteTaker(projectMeeting(response.data));
|
|
2025
2246
|
},
|
|
2026
2247
|
async listMeetings({ organizationId = null, limit = 25, before = null }) {
|
|
2027
2248
|
let query = db.from(TABLES.meetings).select(MEETING_COLUMNS);
|
|
@@ -2782,8 +3003,15 @@ var NO_GRANTS = {
|
|
|
2782
3003
|
canPublish: false,
|
|
2783
3004
|
canSubscribe: false
|
|
2784
3005
|
};
|
|
3006
|
+
var NO_SHARE = { state: "none", reason: null, remedy: null, at: 0 };
|
|
2785
3007
|
var EMPTY = {
|
|
2786
|
-
phase: "
|
|
3008
|
+
phase: "resolving",
|
|
3009
|
+
reason: null,
|
|
3010
|
+
phaseNotice: null,
|
|
3011
|
+
roomName: null,
|
|
3012
|
+
connection: "stable",
|
|
3013
|
+
share: NO_SHARE,
|
|
3014
|
+
call: null,
|
|
2787
3015
|
waiting: null,
|
|
2788
3016
|
meeting: null,
|
|
2789
3017
|
localIdentity: null,
|
|
@@ -2847,8 +3075,20 @@ function createMeetStore(initial = {}) {
|
|
|
2847
3075
|
return () => listeners.delete(listener);
|
|
2848
3076
|
},
|
|
2849
3077
|
patch(next) {
|
|
3078
|
+
if ("phase" in next || "reason" in next || "phaseNotice" in next) {
|
|
3079
|
+
throw new TypeError("meet store: the phase moves only through store.dispatch(event)");
|
|
3080
|
+
}
|
|
2850
3081
|
commit({ ...state, ...next });
|
|
2851
3082
|
},
|
|
3083
|
+
dispatch(event, detail) {
|
|
3084
|
+
const to = nextPhase(state.phase, event);
|
|
3085
|
+
if (to === null) return false;
|
|
3086
|
+
const reason = detail?.reason !== void 0 ? detail.reason : reasonOf(to);
|
|
3087
|
+
const phaseNotice = detail?.notice ?? null;
|
|
3088
|
+
if (to === state.phase && reason === state.reason && phaseNotice === state.phaseNotice) return true;
|
|
3089
|
+
commit({ ...state, phase: to, reason, phaseNotice });
|
|
3090
|
+
return true;
|
|
3091
|
+
},
|
|
2852
3092
|
setParticipants(participants) {
|
|
2853
3093
|
const names = learnNames(state.names, participants);
|
|
2854
3094
|
const hands = new Map(state.participants.map((p) => [p.identity, p.handRaised]));
|
|
@@ -3842,7 +4082,8 @@ function createLiveKitDriver(handlers, options = {}) {
|
|
|
3842
4082
|
}).on(RoomEvent.Disconnected, (reason) => {
|
|
3843
4083
|
audioContainer?.remove();
|
|
3844
4084
|
audioContainer = null;
|
|
3845
|
-
|
|
4085
|
+
const named = reason === void 0 ? null : module?.DisconnectReason?.[reason] ?? String(reason);
|
|
4086
|
+
handlers.disconnected(named);
|
|
3846
4087
|
});
|
|
3847
4088
|
try {
|
|
3848
4089
|
created.registerTextStreamHandler(TRANSCRIPTION_TOPIC, (reader, participantInfo) => {
|
|
@@ -4190,7 +4431,7 @@ function createMeetingSession(options) {
|
|
|
4190
4431
|
}
|
|
4191
4432
|
function apply(read) {
|
|
4192
4433
|
const snapshot = store.snapshot();
|
|
4193
|
-
if (snapshot.phase
|
|
4434
|
+
if (!isWaitingPhase(snapshot.phase)) return;
|
|
4194
4435
|
const admission = read.admission_state ?? null;
|
|
4195
4436
|
const ended = admission === "ended" || read.session_phase === "ended" || read.meeting_phase === "ended";
|
|
4196
4437
|
if (admission === "admitted" && !ended) {
|
|
@@ -4207,6 +4448,7 @@ function createMeetingSession(options) {
|
|
|
4207
4448
|
if (read.meeting_phase === "ended" && meeting !== null && meeting.endedAt === null) {
|
|
4208
4449
|
store.patch({ meeting: { ...meeting, endedAt: (/* @__PURE__ */ new Date()).toISOString() } });
|
|
4209
4450
|
}
|
|
4451
|
+
store.dispatch({ type: "admission", admission: "ended" }, { reason: "ended" });
|
|
4210
4452
|
return;
|
|
4211
4453
|
}
|
|
4212
4454
|
if (admission === null) return;
|
|
@@ -4218,6 +4460,7 @@ function createMeetingSession(options) {
|
|
|
4218
4460
|
pollSeconds: read.poll_seconds ?? snapshot.waiting?.pollSeconds ?? 3,
|
|
4219
4461
|
liveVersion: read.live_version ?? 0
|
|
4220
4462
|
});
|
|
4463
|
+
store.dispatch({ type: "admission", admission });
|
|
4221
4464
|
if (admission === "denied" || admission === "expired" || admission === "withdrawn" || admission === "removed") {
|
|
4222
4465
|
stopWaiting();
|
|
4223
4466
|
}
|
|
@@ -4313,7 +4556,7 @@ function createMeetingSession(options) {
|
|
|
4313
4556
|
// 🚨 PAYLOAD-FREE. Every receiver reads again; a spoofed hint only causes a read.
|
|
4314
4557
|
event: MEET_EVENTS.stateChanged,
|
|
4315
4558
|
onMessage: () => {
|
|
4316
|
-
if (store.snapshot().phase
|
|
4559
|
+
if (isWaitingPhase(store.snapshot().phase)) void readState2();
|
|
4317
4560
|
void refreshQueue();
|
|
4318
4561
|
}
|
|
4319
4562
|
}
|
|
@@ -4325,7 +4568,7 @@ function createMeetingSession(options) {
|
|
|
4325
4568
|
if (meeting === null) return;
|
|
4326
4569
|
const fresh = isGuest(identity) ? await repository.meetingBySlug(meeting.slug) : await readMeeting(meeting.id);
|
|
4327
4570
|
store.patch({ meeting: fresh, locked: fresh.locked });
|
|
4328
|
-
if (store.snapshot().phase
|
|
4571
|
+
if (isWaitingPhase(store.snapshot().phase)) void readState2();
|
|
4329
4572
|
}
|
|
4330
4573
|
});
|
|
4331
4574
|
},
|
|
@@ -4492,10 +4735,34 @@ function createMeetingSession(options) {
|
|
|
4492
4735
|
},
|
|
4493
4736
|
stopWaiting,
|
|
4494
4737
|
readState: readState2,
|
|
4738
|
+
async readExit(connection) {
|
|
4739
|
+
const meeting = store.snapshot().meeting;
|
|
4740
|
+
const pass = options.resolvePass?.() ?? null;
|
|
4741
|
+
if (meeting === null || pass === null) return void 0;
|
|
4742
|
+
try {
|
|
4743
|
+
const response = await options.api.request({
|
|
4744
|
+
path: `${MEET_ROUTES.state}?meeting_id=${encodeURIComponent(meeting.id)}&connection=${encodeURIComponent(connection)}`,
|
|
4745
|
+
method: "GET",
|
|
4746
|
+
requireAuth: false,
|
|
4747
|
+
operation: "meet.state(exit)",
|
|
4748
|
+
headers: { [MEETING_PASS_HEADER]: pass }
|
|
4749
|
+
});
|
|
4750
|
+
if (!response.ok) return null;
|
|
4751
|
+
const read = await response.json();
|
|
4752
|
+
return {
|
|
4753
|
+
exitReason: read.exit_reason ?? null,
|
|
4754
|
+
sessionPhase: read.session_phase ?? null,
|
|
4755
|
+
meetingPhase: read.meeting_phase ?? null
|
|
4756
|
+
};
|
|
4757
|
+
} catch {
|
|
4758
|
+
return null;
|
|
4759
|
+
}
|
|
4760
|
+
},
|
|
4495
4761
|
async withdraw() {
|
|
4496
4762
|
stopWaiting();
|
|
4497
4763
|
await postLeave("withdraw");
|
|
4498
4764
|
patchWaiting({ admission: "withdrawn" });
|
|
4765
|
+
store.dispatch({ type: "admission", admission: "withdrawn" });
|
|
4499
4766
|
hint();
|
|
4500
4767
|
},
|
|
4501
4768
|
async askAgain() {
|
|
@@ -5119,6 +5386,9 @@ async function pushMeetingToGoogleCalendar(api, meetingId, target) {
|
|
|
5119
5386
|
}
|
|
5120
5387
|
|
|
5121
5388
|
// src/core/room.ts
|
|
5389
|
+
function SCREEN_SHARE_BLOCKED_REMEDY_FOR(remedy) {
|
|
5390
|
+
return /administrator|policy/i.test(remedy) ? remedy : SCREEN_SHARE_BLOCKED_REMEDY;
|
|
5391
|
+
}
|
|
5122
5392
|
var PARTICIPANT_ROLE_ATTRIBUTE = "matrx.participant.role";
|
|
5123
5393
|
var PARTICIPANT_CAN_RECORD_ATTRIBUTE = "matrx.participant.can_record";
|
|
5124
5394
|
var PARTICIPANT_STANDING_ATTRIBUTE = "matrx.participant.standing";
|
|
@@ -5186,7 +5456,7 @@ function createRoomEngine(options) {
|
|
|
5186
5456
|
let disposed = false;
|
|
5187
5457
|
let moving = false;
|
|
5188
5458
|
const confirmingEnds = /* @__PURE__ */ new WeakSet();
|
|
5189
|
-
async function
|
|
5459
|
+
async function dropRoom() {
|
|
5190
5460
|
const target = driver;
|
|
5191
5461
|
driver = null;
|
|
5192
5462
|
if (current !== null) {
|
|
@@ -5195,9 +5465,14 @@ function createRoomEngine(options) {
|
|
|
5195
5465
|
}
|
|
5196
5466
|
store.setLocalTrack("microphone", IDLE_TRACK);
|
|
5197
5467
|
store.setLocalTrack("camera", IDLE_TRACK);
|
|
5198
|
-
store.patch({
|
|
5468
|
+
store.patch({ share: NO_SHARE, connection: "stable" });
|
|
5199
5469
|
await target?.disconnect();
|
|
5200
5470
|
}
|
|
5471
|
+
async function leaveRoom() {
|
|
5472
|
+
store.dispatch({ type: "leave" });
|
|
5473
|
+
await dropRoom();
|
|
5474
|
+
options.onLeft?.(null);
|
|
5475
|
+
}
|
|
5201
5476
|
async function confirmMeetingEnd() {
|
|
5202
5477
|
const meeting = store.snapshot().meeting;
|
|
5203
5478
|
const target = driver;
|
|
@@ -5219,7 +5494,9 @@ function createRoomEngine(options) {
|
|
|
5219
5494
|
const latest = store.snapshot().meeting;
|
|
5220
5495
|
if (latest === null) return;
|
|
5221
5496
|
store.patch({ meeting: { ...latest, endedAt: verified.endedAt } });
|
|
5222
|
-
|
|
5497
|
+
store.dispatch({ type: "ended" }, { reason: "ended" });
|
|
5498
|
+
await dropRoom();
|
|
5499
|
+
options.onLeft?.("ended");
|
|
5223
5500
|
} catch (error) {
|
|
5224
5501
|
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.");
|
|
5225
5502
|
} finally {
|
|
@@ -5231,12 +5508,12 @@ function createRoomEngine(options) {
|
|
|
5231
5508
|
options.onDiagnostic?.(remedy === void 0 ? { level, message } : { level, message, remedy });
|
|
5232
5509
|
}
|
|
5233
5510
|
let ambiguousShareDenials = 0;
|
|
5234
|
-
function
|
|
5511
|
+
function failJoin(error, operation) {
|
|
5235
5512
|
const normalized = normalizeMeetError(error, operation);
|
|
5236
5513
|
store.patch({
|
|
5237
|
-
phase: "failed",
|
|
5238
5514
|
failure: { message: normalized.message, remedy: normalized.remedy, reason: normalized.reason }
|
|
5239
5515
|
});
|
|
5516
|
+
store.dispatch({ type: "join_failed", reason: normalized.reason ?? null });
|
|
5240
5517
|
report(
|
|
5241
5518
|
normalized.code === "session-unavailable" ? "warn" : "error",
|
|
5242
5519
|
normalized.message,
|
|
@@ -5244,6 +5521,14 @@ function createRoomEngine(options) {
|
|
|
5244
5521
|
);
|
|
5245
5522
|
return normalized;
|
|
5246
5523
|
}
|
|
5524
|
+
async function lostRoom(error, operation) {
|
|
5525
|
+
const normalized = normalizeMeetError(error, operation);
|
|
5526
|
+
store.patch({ failure: { message: normalized.message, remedy: normalized.remedy, reason: normalized.reason } });
|
|
5527
|
+
await dropRoom();
|
|
5528
|
+
store.dispatch({ type: "exit", to: "disconnected" });
|
|
5529
|
+
report("error", normalized.message, normalized.remedy);
|
|
5530
|
+
return normalized;
|
|
5531
|
+
}
|
|
5247
5532
|
const handlers = {
|
|
5248
5533
|
participants(list) {
|
|
5249
5534
|
const joinedAt = new Date(now()).toISOString();
|
|
@@ -5286,9 +5571,12 @@ function createRoomEngine(options) {
|
|
|
5286
5571
|
store.setQuality(asParticipantIdentity(who), value);
|
|
5287
5572
|
},
|
|
5288
5573
|
connectionState(state) {
|
|
5289
|
-
if (state === "connected")
|
|
5290
|
-
|
|
5291
|
-
|
|
5574
|
+
if (state === "connected") {
|
|
5575
|
+
if (store.snapshot().connection !== "stable") store.patch({ connection: "stable" });
|
|
5576
|
+
store.dispatch({ type: "connected" });
|
|
5577
|
+
} else if (state === "reconnecting") {
|
|
5578
|
+
store.patch({ connection: "reconnecting" });
|
|
5579
|
+
}
|
|
5292
5580
|
},
|
|
5293
5581
|
transcription(event) {
|
|
5294
5582
|
const snapshot = store.snapshot();
|
|
@@ -5415,17 +5703,48 @@ function createRoomEngine(options) {
|
|
|
5415
5703
|
}
|
|
5416
5704
|
},
|
|
5417
5705
|
disconnected(reason) {
|
|
5418
|
-
if (moving) return;
|
|
5419
|
-
|
|
5420
|
-
tokens.invalidate(current.roomName);
|
|
5421
|
-
current = null;
|
|
5422
|
-
}
|
|
5423
|
-
store.patch({ phase: "left" });
|
|
5424
|
-
options.onLeft?.(reason);
|
|
5706
|
+
if (moving || driver === null) return;
|
|
5707
|
+
void resolveExitAndApply(reason);
|
|
5425
5708
|
}
|
|
5426
5709
|
};
|
|
5710
|
+
async function resolveExitAndApply(hint) {
|
|
5711
|
+
const connection = current?.identity ?? store.snapshot().localIdentity ?? null;
|
|
5712
|
+
await dropRoom();
|
|
5713
|
+
let server;
|
|
5714
|
+
if (options.readExit === void 0 || connection === null || store.snapshot().meeting === null) {
|
|
5715
|
+
server = void 0;
|
|
5716
|
+
} else {
|
|
5717
|
+
try {
|
|
5718
|
+
server = await options.readExit(connection);
|
|
5719
|
+
} catch {
|
|
5720
|
+
server = null;
|
|
5721
|
+
}
|
|
5722
|
+
}
|
|
5723
|
+
if (disposed) return;
|
|
5724
|
+
const resolved = resolveExit({ server, hint, frozen: options.wasFrozen?.() ?? false });
|
|
5725
|
+
store.patch({ connection: resolved.connection });
|
|
5726
|
+
if (resolved.to === "waiting:knocking") {
|
|
5727
|
+
store.patch({
|
|
5728
|
+
waiting: {
|
|
5729
|
+
admission: "knocking",
|
|
5730
|
+
admittersPresent: null,
|
|
5731
|
+
reknockAllowed: true,
|
|
5732
|
+
knockExpiresAt: null,
|
|
5733
|
+
pollSeconds: store.snapshot().waiting?.pollSeconds ?? 3,
|
|
5734
|
+
liveVersion: 0
|
|
5735
|
+
}
|
|
5736
|
+
});
|
|
5737
|
+
}
|
|
5738
|
+
store.dispatch({ type: "exit", to: resolved.to }, { reason: resolved.reason, notice: resolved.notice });
|
|
5739
|
+
report(
|
|
5740
|
+
resolved.to === "disconnected" ? "warn" : "info",
|
|
5741
|
+
`meet: the room connection ended (${hint ?? "no LiveKit reason"}) \u2192 ${resolved.to}`,
|
|
5742
|
+
resolved.to === "disconnected" ? "Press Rejoin; the meeting is still going." : "The screen says what happened."
|
|
5743
|
+
);
|
|
5744
|
+
options.onLeft?.(hint);
|
|
5745
|
+
}
|
|
5427
5746
|
async function connect(request) {
|
|
5428
|
-
store.patch({
|
|
5747
|
+
store.patch({ failure: null, waiting: null, roomName: request.roomName, share: NO_SHARE, connection: "stable" });
|
|
5429
5748
|
const token = await tokens.get({
|
|
5430
5749
|
roomName: request.roomName,
|
|
5431
5750
|
identity,
|
|
@@ -5448,10 +5767,10 @@ function createRoomEngine(options) {
|
|
|
5448
5767
|
}
|
|
5449
5768
|
});
|
|
5450
5769
|
if (token.lobby || !token.canSubscribe) {
|
|
5770
|
+
const admission = token.admissionState !== void 0 && token.admissionState !== "admitted" ? token.admissionState : "knocking";
|
|
5451
5771
|
store.patch({
|
|
5452
|
-
phase: "lobby",
|
|
5453
5772
|
waiting: {
|
|
5454
|
-
admission
|
|
5773
|
+
admission,
|
|
5455
5774
|
admittersPresent: null,
|
|
5456
5775
|
reknockAllowed: true,
|
|
5457
5776
|
knockExpiresAt: null,
|
|
@@ -5459,9 +5778,10 @@ function createRoomEngine(options) {
|
|
|
5459
5778
|
liveVersion: 0
|
|
5460
5779
|
}
|
|
5461
5780
|
});
|
|
5781
|
+
store.dispatch({ type: "admission", admission });
|
|
5462
5782
|
return;
|
|
5463
5783
|
}
|
|
5464
|
-
store.patch({
|
|
5784
|
+
store.patch({ waiting: null });
|
|
5465
5785
|
const created = await options.driverFactory(handlers);
|
|
5466
5786
|
if (disposed) {
|
|
5467
5787
|
await created.disconnect();
|
|
@@ -5469,7 +5789,8 @@ function createRoomEngine(options) {
|
|
|
5469
5789
|
}
|
|
5470
5790
|
driver = created;
|
|
5471
5791
|
await created.connect(token.serverUrl, token.token);
|
|
5472
|
-
store.patch({
|
|
5792
|
+
store.patch({ failure: null, connection: "stable" });
|
|
5793
|
+
store.dispatch({ type: "connected" });
|
|
5473
5794
|
store.setLocalTrack("microphone", IDLE_TRACK);
|
|
5474
5795
|
store.setLocalTrack("camera", IDLE_TRACK);
|
|
5475
5796
|
const effects = options.effectsStorage?.load() ?? store.snapshot().effects;
|
|
@@ -5540,9 +5861,17 @@ function createRoomEngine(options) {
|
|
|
5540
5861
|
return {
|
|
5541
5862
|
join(request) {
|
|
5542
5863
|
if (joining !== null) return joining;
|
|
5864
|
+
if (store.snapshot().phase !== "joining" && !store.dispatch({ type: "join", click: true })) {
|
|
5865
|
+
report(
|
|
5866
|
+
"warn",
|
|
5867
|
+
`meet.join: cannot join from "${store.snapshot().phase}"`,
|
|
5868
|
+
"Join is offered from the pre-join, left, disconnected and replaced screens only."
|
|
5869
|
+
);
|
|
5870
|
+
return Promise.resolve();
|
|
5871
|
+
}
|
|
5543
5872
|
lastRequest = request;
|
|
5544
5873
|
joining = connect(request).catch((error) => {
|
|
5545
|
-
throw
|
|
5874
|
+
throw failJoin(error, "meet.join");
|
|
5546
5875
|
}).finally(() => {
|
|
5547
5876
|
joining = null;
|
|
5548
5877
|
});
|
|
@@ -5559,10 +5888,16 @@ function createRoomEngine(options) {
|
|
|
5559
5888
|
return;
|
|
5560
5889
|
}
|
|
5561
5890
|
if (joining !== null) return joining;
|
|
5891
|
+
const phase = store.snapshot().phase;
|
|
5892
|
+
const moved = phase === "joining" || store.dispatch({ type: "join", click: true }) || store.dispatch({ type: "admitted" });
|
|
5893
|
+
if (!moved) {
|
|
5894
|
+
report("warn", `meet.rejoin: cannot rejoin from "${phase}"`, "Rejoin is offered after leaving, a lost connection, or admission.");
|
|
5895
|
+
return;
|
|
5896
|
+
}
|
|
5562
5897
|
tokens.invalidate(request.roomName);
|
|
5563
5898
|
current = null;
|
|
5564
5899
|
joining = connect(request).catch((error) => {
|
|
5565
|
-
throw
|
|
5900
|
+
throw failJoin(error, "meet.rejoin");
|
|
5566
5901
|
}).finally(() => {
|
|
5567
5902
|
joining = null;
|
|
5568
5903
|
});
|
|
@@ -5607,11 +5942,11 @@ function createRoomEngine(options) {
|
|
|
5607
5942
|
joining = connect(lastRequest).finally(() => {
|
|
5608
5943
|
joining = null;
|
|
5609
5944
|
});
|
|
5610
|
-
await joining.catch((again) => {
|
|
5611
|
-
throw
|
|
5945
|
+
await joining.catch(async (again) => {
|
|
5946
|
+
throw await lostRoom(again, "meet.moveToBreakout");
|
|
5612
5947
|
});
|
|
5613
5948
|
} else {
|
|
5614
|
-
throw
|
|
5949
|
+
throw await lostRoom(error, "meet.moveToBreakout");
|
|
5615
5950
|
}
|
|
5616
5951
|
throw normalized;
|
|
5617
5952
|
} finally {
|
|
@@ -5619,6 +5954,9 @@ function createRoomEngine(options) {
|
|
|
5619
5954
|
}
|
|
5620
5955
|
},
|
|
5621
5956
|
leave: leaveRoom,
|
|
5957
|
+
backToPrejoin() {
|
|
5958
|
+
store.dispatch({ type: "back_to_prejoin", click: true });
|
|
5959
|
+
},
|
|
5622
5960
|
// Turning a device on mid-meeting is the SAME operation as turning it on
|
|
5623
5961
|
// during the join, so it runs the same function. A failure here used to
|
|
5624
5962
|
// stamp the room `failed` — a busy microphone would blank a live meeting.
|
|
@@ -5632,21 +5970,41 @@ function createRoomEngine(options) {
|
|
|
5632
5970
|
},
|
|
5633
5971
|
async setScreenShareEnabled(enabled) {
|
|
5634
5972
|
if (driver === null) return;
|
|
5973
|
+
if (enabled && driver.supportsScreenShare?.() === false) {
|
|
5974
|
+
store.patch({ share: { state: "refused", reason: "unsupported", remedy: null, at: now() } });
|
|
5975
|
+
report("warn", "meet: this browser cannot share a screen", "Share from a desktop browser (Chrome, Edge, Firefox or Safari).");
|
|
5976
|
+
return;
|
|
5977
|
+
}
|
|
5978
|
+
if (enabled) store.patch({ share: { state: "picking", reason: null, remedy: null, at: now() } });
|
|
5635
5979
|
try {
|
|
5636
5980
|
await driver.setScreenShareEnabled(enabled);
|
|
5637
5981
|
ambiguousShareDenials = 0;
|
|
5982
|
+
store.patch({ share: { state: enabled ? "presenting" : "none", reason: null, remedy: null, at: now() } });
|
|
5638
5983
|
} catch (error) {
|
|
5639
5984
|
const kind = classifyScreenShareError(error);
|
|
5640
5985
|
if (kind === "ambiguous") {
|
|
5641
5986
|
ambiguousShareDenials += 1;
|
|
5642
|
-
if (ambiguousShareDenials < 2)
|
|
5987
|
+
if (ambiguousShareDenials < 2) {
|
|
5988
|
+
store.patch({ share: NO_SHARE });
|
|
5989
|
+
return;
|
|
5990
|
+
}
|
|
5643
5991
|
}
|
|
5992
|
+
ambiguousShareDenials = 0;
|
|
5644
5993
|
const normalized = normalizeScreenShareError(error, "meet.setScreenShareEnabled");
|
|
5645
5994
|
report("warn", normalized.message, normalized.remedy);
|
|
5646
|
-
|
|
5647
|
-
|
|
5995
|
+
store.patch({
|
|
5996
|
+
share: {
|
|
5997
|
+
state: "refused",
|
|
5998
|
+
reason: kind === "other" ? "failed" : "blocked",
|
|
5999
|
+
remedy: kind === "other" ? normalized.remedy : SCREEN_SHARE_BLOCKED_REMEDY_FOR(normalized.remedy),
|
|
6000
|
+
at: now()
|
|
6001
|
+
}
|
|
6002
|
+
});
|
|
5648
6003
|
}
|
|
5649
6004
|
},
|
|
6005
|
+
dismissShareNotice() {
|
|
6006
|
+
if (store.snapshot().share.state === "refused") store.patch({ share: NO_SHARE });
|
|
6007
|
+
},
|
|
5650
6008
|
async raiseHand(raised) {
|
|
5651
6009
|
const local = store.snapshot().localIdentity;
|
|
5652
6010
|
if (local !== null) store.setHand(local, raised);
|
|
@@ -6613,28 +6971,6 @@ function createMeetingRecordCache(options = {}) {
|
|
|
6613
6971
|
};
|
|
6614
6972
|
}
|
|
6615
6973
|
|
|
6616
|
-
// src/core/reasons.ts
|
|
6617
|
-
var JOIN_REFUSAL_REASONS = [
|
|
6618
|
-
"not_found",
|
|
6619
|
-
"cancelled",
|
|
6620
|
-
"ended",
|
|
6621
|
-
"expired",
|
|
6622
|
-
"too_early",
|
|
6623
|
-
"sign_in_required",
|
|
6624
|
-
"wrong_account",
|
|
6625
|
-
"not_invited",
|
|
6626
|
-
"locked",
|
|
6627
|
-
"removed",
|
|
6628
|
-
"lobby_rejects",
|
|
6629
|
-
"meeting_full",
|
|
6630
|
-
"platform_capacity",
|
|
6631
|
-
"verification_required",
|
|
6632
|
-
"registration_required"
|
|
6633
|
-
];
|
|
6634
|
-
function isJoinRefusalReason(value) {
|
|
6635
|
-
return typeof value === "string" && JOIN_REFUSAL_REASONS.includes(value);
|
|
6636
|
-
}
|
|
6637
|
-
|
|
6638
6974
|
// src/core/reactions.ts
|
|
6639
6975
|
var MEET_REACTIONS = ["\u{1F496}", "\u{1F44D}", "\u{1F389}", "\u{1F44F}", "\u{1F602}", "\u{1F62E}", "\u{1F622}", "\u{1F914}", "\u{1F44E}"];
|
|
6640
6976
|
|
|
@@ -6733,43 +7069,12 @@ function endedRecord(snapshot, given) {
|
|
|
6733
7069
|
function observedPhase(input) {
|
|
6734
7070
|
const { snapshot } = input;
|
|
6735
7071
|
if (snapshot === null) return "resolving";
|
|
6736
|
-
const
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
const reason = raw === "failed" ? snapshot.failure?.reason ?? null : null;
|
|
6740
|
-
if (reason !== null) return reason === "ended" ? "ended" : `refused:${reason}`;
|
|
6741
|
-
switch (raw) {
|
|
6742
|
-
case "idle":
|
|
6743
|
-
case "failed":
|
|
6744
|
-
case "left":
|
|
6745
|
-
return "prejoin";
|
|
6746
|
-
case "lobby":
|
|
6747
|
-
return waitingPhase(snapshot);
|
|
6748
|
-
case "requesting-token":
|
|
6749
|
-
case "connecting":
|
|
6750
|
-
return "joining";
|
|
6751
|
-
case "connected":
|
|
6752
|
-
case "reconnecting":
|
|
6753
|
-
return "in_call";
|
|
6754
|
-
}
|
|
7072
|
+
const phase = snapshot.phase;
|
|
7073
|
+
if (endedRecord(snapshot, input.meeting ?? null) && !isLivePhase(phase) && !isCallPhase(phase)) return "ended";
|
|
7074
|
+
return phase;
|
|
6755
7075
|
}
|
|
6756
|
-
function
|
|
6757
|
-
|
|
6758
|
-
case "waiting_host":
|
|
6759
|
-
return "waiting:host_not_started";
|
|
6760
|
-
case "denied":
|
|
6761
|
-
return "denied";
|
|
6762
|
-
case "expired":
|
|
6763
|
-
return "knock_expired";
|
|
6764
|
-
case "withdrawn":
|
|
6765
|
-
return "left";
|
|
6766
|
-
case "ended":
|
|
6767
|
-
return "ended";
|
|
6768
|
-
case "removed":
|
|
6769
|
-
return "refused:removed";
|
|
6770
|
-
default:
|
|
6771
|
-
return "waiting:knocking";
|
|
6772
|
-
}
|
|
7076
|
+
function isCallPhase(phase) {
|
|
7077
|
+
return phase.startsWith("ringing_") || phase.startsWith("call_") || phase === "answered_elsewhere";
|
|
6773
7078
|
}
|
|
6774
7079
|
var ADMITTER_ROLES = /* @__PURE__ */ new Set(["host", "cohost"]);
|
|
6775
7080
|
function observe(input) {
|
|
@@ -6782,10 +7087,10 @@ function observe(input) {
|
|
|
6782
7087
|
const deviceInPlay = phase === "joining" || inCall;
|
|
6783
7088
|
return {
|
|
6784
7089
|
phase,
|
|
6785
|
-
reason: phase
|
|
7090
|
+
reason: phase === "ended" ? snapshot?.reason ?? null : snapshot?.reason ?? reasonOf(phase),
|
|
6786
7091
|
role,
|
|
6787
|
-
connection: snapshot?.
|
|
6788
|
-
hostPresent: inCall && snapshot !== null ? snapshot.participants.some((p) => ADMITTER_ROLES.has(p.role)) : snapshot
|
|
7092
|
+
connection: snapshot?.connection ?? "stable",
|
|
7093
|
+
hostPresent: inCall && snapshot !== null ? snapshot.participants.some((p) => ADMITTER_ROLES.has(p.role)) : snapshot !== null && isWaitingPhase(snapshot.phase) ? snapshot.waiting?.admittersPresent ?? null : null,
|
|
6789
7094
|
lobbyCount: canAdmit && snapshot !== null ? snapshot.lobby.filter((entry) => entry.state === "knocking").length : 0,
|
|
6790
7095
|
recording: snapshot?.recording === "recording" || snapshot?.recording === "stopping",
|
|
6791
7096
|
audioBlocked: null,
|
|
@@ -6877,9 +7182,11 @@ export {
|
|
|
6877
7182
|
GUEST_RECORD_ACCESS_METADATA_KEY,
|
|
6878
7183
|
GUEST_RECORD_NOT_SHARED,
|
|
6879
7184
|
IDLE_MEDIA,
|
|
7185
|
+
IDLE_PHASES,
|
|
6880
7186
|
IDLE_TRACK,
|
|
6881
7187
|
JOIN_REFUSAL_REASONS,
|
|
6882
7188
|
LISTEN_ONLY_NOTICE,
|
|
7189
|
+
LIVE_PHASES,
|
|
6883
7190
|
MEETING_INVITE_KIND,
|
|
6884
7191
|
MEETING_INVITE_VERSION,
|
|
6885
7192
|
MEETING_PASS_HEADER,
|
|
@@ -6895,6 +7202,7 @@ export {
|
|
|
6895
7202
|
NOTE_TAKER_IDENTITY_PREFIX,
|
|
6896
7203
|
NOTE_TAKER_METADATA_KEY,
|
|
6897
7204
|
NO_GRANTS,
|
|
7205
|
+
NO_SHARE,
|
|
6898
7206
|
ORGANIZATION_HEADER,
|
|
6899
7207
|
PARTICIPANT_CAN_RECORD_ATTRIBUTE,
|
|
6900
7208
|
PARTICIPANT_ROLE_ATTRIBUTE,
|
|
@@ -6908,9 +7216,11 @@ export {
|
|
|
6908
7216
|
TABLES,
|
|
6909
7217
|
TRANSCRIPTION_ATTRIBUTES,
|
|
6910
7218
|
TRANSCRIPTION_TOPIC,
|
|
7219
|
+
WAITING_PHASES,
|
|
6911
7220
|
absenceSentence,
|
|
6912
7221
|
activeWrapUpSummary,
|
|
6913
7222
|
activityAttention,
|
|
7223
|
+
admissionPhase,
|
|
6914
7224
|
announceMeeting,
|
|
6915
7225
|
appPanelOf,
|
|
6916
7226
|
applyCollabPacket,
|
|
@@ -6980,10 +7290,13 @@ export {
|
|
|
6980
7290
|
isJoinRefusalReason,
|
|
6981
7291
|
isLinkFollower,
|
|
6982
7292
|
isListenOnly,
|
|
7293
|
+
isLivePhase,
|
|
6983
7294
|
isNoteTaker,
|
|
6984
7295
|
isObserverRole,
|
|
6985
7296
|
isRealName,
|
|
7297
|
+
isRefusedPhase,
|
|
6986
7298
|
isRoomEventTopic,
|
|
7299
|
+
isWaitingPhase,
|
|
6987
7300
|
learnName,
|
|
6988
7301
|
learnNames,
|
|
6989
7302
|
listenOnlyNotice,
|
|
@@ -7007,6 +7320,7 @@ export {
|
|
|
7007
7320
|
mergeRecord,
|
|
7008
7321
|
microphoneNoticeCode,
|
|
7009
7322
|
moveToRoom,
|
|
7323
|
+
nextPhase,
|
|
7010
7324
|
nextTranslationBatch,
|
|
7011
7325
|
normalizeDeviceError,
|
|
7012
7326
|
normalizeMeetError,
|
|
@@ -7039,10 +7353,13 @@ export {
|
|
|
7039
7353
|
pushMeetingToGoogleCalendar,
|
|
7040
7354
|
readServerRefusal,
|
|
7041
7355
|
readableTranscript,
|
|
7356
|
+
reasonOf,
|
|
7042
7357
|
recordingLabel,
|
|
7043
7358
|
recordingNotice,
|
|
7044
7359
|
recordingOffsetMs,
|
|
7360
|
+
refusalPhase,
|
|
7045
7361
|
rememberedMeetingPass,
|
|
7362
|
+
resolveExit,
|
|
7046
7363
|
roleOf,
|
|
7047
7364
|
roomTopic,
|
|
7048
7365
|
rootAttributes,
|