@ai-matrx/meet 0.10.0 → 0.10.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-C2R-kQnV.d.cts → collab-BBQxcyRQ.d.cts} +47 -1
- package/dist/{collab-C2R-kQnV.d.ts → collab-BBQxcyRQ.d.ts} +47 -1
- package/dist/{components-CMtSekZS.d.ts → components-1XBHgMYK.d.ts} +6 -2
- package/dist/{components-DKHfkEVB.d.cts → components-CK0EyqGL.d.cts} +6 -2
- package/dist/core.cjs +506 -455
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +24 -4
- package/dist/core.d.ts +24 -4
- package/dist/core.js +506 -455
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +506 -455
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +506 -455
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +2988 -2856
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +67 -5
- package/dist/react.d.ts +67 -5
- package/dist/react.js +2650 -2518
- package/dist/react.js.map +1 -1
- package/dist/skins/meet.cjs +974 -909
- 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 +618 -553
- package/dist/skins/meet.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -387,7 +387,8 @@ function parseRoomToken(body, roomName) {
|
|
|
387
387
|
lobby: readBoolean(payload, "lobby", false),
|
|
388
388
|
admissionState: readString(payload, "admission_state") ?? void 0,
|
|
389
389
|
pollSeconds: typeof payload["poll_seconds"] === "number" ? payload["poll_seconds"] : void 0,
|
|
390
|
-
breakoutRoomId: readString(payload, "breakout_room_id") ?? null
|
|
390
|
+
breakoutRoomId: readString(payload, "breakout_room_id") ?? null,
|
|
391
|
+
observersVisibleTo: readString(payload, "observers_visible_to") === "hosts" ? "hosts" : "everyone"
|
|
391
392
|
};
|
|
392
393
|
}
|
|
393
394
|
function createTokenClient(options) {
|
|
@@ -436,6 +437,7 @@ function createTokenClient(options) {
|
|
|
436
437
|
...input.meetingId !== void 0 ? { meeting_id: input.meetingId } : {},
|
|
437
438
|
...input.slug !== void 0 ? { slug: input.slug } : {},
|
|
438
439
|
...input.breakoutRoomId != null ? { breakout_room_id: input.breakoutRoomId } : {},
|
|
440
|
+
...input.observe === true ? { observe: true } : {},
|
|
439
441
|
organization_id: input.identity.organizationId,
|
|
440
442
|
display_name: input.identity.displayName,
|
|
441
443
|
device_id: input.identity.deviceId,
|
|
@@ -507,7 +509,8 @@ function createTokenClient(options) {
|
|
|
507
509
|
return {
|
|
508
510
|
get(input) {
|
|
509
511
|
const entry = cache.get(input.roomName);
|
|
510
|
-
const sameRoom = entry !== void 0 && (entry.token.breakoutRoomId ?? null) === (input.breakoutRoomId ?? null)
|
|
512
|
+
const sameRoom = entry !== void 0 && (entry.token.breakoutRoomId ?? null) === (input.breakoutRoomId ?? null) && // An observer's pass is not a participant's, and back (MD-16).
|
|
513
|
+
entry.token.role === "viewer" === (input.observe === true);
|
|
511
514
|
if (entry !== void 0 && sameRoom) {
|
|
512
515
|
if (entry.inFlight !== null) return entry.inFlight;
|
|
513
516
|
if (!expired(entry)) return Promise.resolve(entry.token);
|
|
@@ -1033,6 +1036,9 @@ function isLinkFollower(standing) {
|
|
|
1033
1036
|
function isHostRole(role) {
|
|
1034
1037
|
return role === "host" || role === "cohost";
|
|
1035
1038
|
}
|
|
1039
|
+
function isObserverRole(role) {
|
|
1040
|
+
return role === "viewer";
|
|
1041
|
+
}
|
|
1036
1042
|
var WAITING_ADMISSION_STATES = ["waiting_host", "knocking"];
|
|
1037
1043
|
|
|
1038
1044
|
// src/core/calls.ts
|
|
@@ -1237,388 +1243,49 @@ function createCallCenter(options) {
|
|
|
1237
1243
|
);
|
|
1238
1244
|
return invite;
|
|
1239
1245
|
},
|
|
1240
|
-
async accept(id, mode) {
|
|
1241
|
-
const held = incoming.get(id);
|
|
1242
|
-
if (held !== void 0 && !canTransition(held.state, "connecting")) {
|
|
1243
|
-
throw new MeetError(
|
|
1244
|
-
"conflict",
|
|
1245
|
-
`meet.calls.accept: this call is already ${held.state}`,
|
|
1246
|
-
"A late accept must not resurrect a settled call. Close the ringing UI; the caller has already moved on."
|
|
1247
|
-
);
|
|
1248
|
-
}
|
|
1249
|
-
const settled = await repository.settleCallInvite(id, "connecting", null);
|
|
1250
|
-
settleLocal(settled);
|
|
1251
|
-
channel?.send(MEET_EVENTS.settled, settled);
|
|
1252
|
-
to(settled.callerUserId).send(MEET_EVENTS.settled, { ...settled, mode });
|
|
1253
|
-
return settled;
|
|
1254
|
-
},
|
|
1255
|
-
async decline(id, message) {
|
|
1256
|
-
const settled = await repository.settleCallInvite(id, "declined", message ?? null);
|
|
1257
|
-
settleLocal(settled);
|
|
1258
|
-
channel?.send(MEET_EVENTS.settled, settled);
|
|
1259
|
-
to(settled.callerUserId).send(MEET_EVENTS.settled, settled);
|
|
1260
|
-
return settled;
|
|
1261
|
-
},
|
|
1262
|
-
async cancel(id) {
|
|
1263
|
-
const settled = await repository.settleCallInvite(id, "cancelled", null);
|
|
1264
|
-
clearRing(id);
|
|
1265
|
-
if (outgoing?.id === id) outgoing = settled;
|
|
1266
|
-
for (const callee of settled.calleeUserIds) {
|
|
1267
|
-
to(callee).send(MEET_EVENTS.cancel, settled);
|
|
1268
|
-
}
|
|
1269
|
-
return settled;
|
|
1270
|
-
},
|
|
1271
|
-
incoming: () => [...incoming.values()],
|
|
1272
|
-
outgoing: () => outgoing,
|
|
1273
|
-
ingest,
|
|
1274
|
-
dispose() {
|
|
1275
|
-
for (const id of [...timeouts.keys()]) clearRing(asCallId(id));
|
|
1276
|
-
incoming.clear();
|
|
1277
|
-
for (const handle of outbound.values()) handle.close();
|
|
1278
|
-
outbound.clear();
|
|
1279
|
-
channel?.close();
|
|
1280
|
-
channel = null;
|
|
1281
|
-
}
|
|
1282
|
-
};
|
|
1283
|
-
}
|
|
1284
|
-
|
|
1285
|
-
// src/core/collab.ts
|
|
1286
|
-
var EMPTY_COLLAB = {
|
|
1287
|
-
loaded: false,
|
|
1288
|
-
error: null,
|
|
1289
|
-
settings: null,
|
|
1290
|
-
polls: [],
|
|
1291
|
-
questions: [],
|
|
1292
|
-
strokes: [],
|
|
1293
|
-
breakout: null,
|
|
1294
|
-
broadcast: null,
|
|
1295
|
-
moveRequest: null,
|
|
1296
|
-
panelRequest: null,
|
|
1297
|
-
captionLanguage: null,
|
|
1298
|
-
captionTranslations: {},
|
|
1299
|
-
captionTranslationError: null
|
|
1300
|
-
};
|
|
1301
|
-
function obj(value) {
|
|
1302
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
1303
|
-
}
|
|
1304
|
-
function str(value) {
|
|
1305
|
-
return typeof value === "string" ? value : null;
|
|
1306
|
-
}
|
|
1307
|
-
function num(value) {
|
|
1308
|
-
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
1309
|
-
}
|
|
1310
|
-
function strings(value) {
|
|
1311
|
-
return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
1312
|
-
}
|
|
1313
|
-
function pollFromRow(row) {
|
|
1314
|
-
const id = str(row["id"]);
|
|
1315
|
-
if (id === null) return null;
|
|
1316
|
-
const options = [];
|
|
1317
|
-
for (const raw of Array.isArray(row["options"]) ? row["options"] : []) {
|
|
1318
|
-
const option = obj(raw);
|
|
1319
|
-
const optionId = option === null ? null : str(option["id"]);
|
|
1320
|
-
if (option === null || optionId === null) continue;
|
|
1321
|
-
const votes = num(option["votes"]);
|
|
1322
|
-
options.push({
|
|
1323
|
-
id: optionId,
|
|
1324
|
-
text: str(option["text"]) ?? "",
|
|
1325
|
-
...votes !== null ? { votes } : {},
|
|
1326
|
-
...Array.isArray(option["voters"]) ? { voters: strings(option["voters"]) } : {}
|
|
1327
|
-
});
|
|
1328
|
-
}
|
|
1329
|
-
const state = str(row["state"]);
|
|
1330
|
-
return {
|
|
1331
|
-
id,
|
|
1332
|
-
question: str(row["question"]) ?? "",
|
|
1333
|
-
options,
|
|
1334
|
-
multiple: row["multiple"] === true,
|
|
1335
|
-
anonymous: row["anonymous"] === true,
|
|
1336
|
-
state: state === "live" || state === "closed" ? state : "draft",
|
|
1337
|
-
resultsShared: row["results_shared"] === true,
|
|
1338
|
-
voterCount: num(row["voter_count"]),
|
|
1339
|
-
myVote: strings(row["my_vote"]),
|
|
1340
|
-
createdByName: str(row["created_by_name"]) ?? "",
|
|
1341
|
-
createdAt: str(row["created_at"])
|
|
1342
|
-
};
|
|
1343
|
-
}
|
|
1344
|
-
function questionFromRow(row) {
|
|
1345
|
-
const id = str(row["id"]);
|
|
1346
|
-
if (id === null) return null;
|
|
1347
|
-
const state = str(row["state"]);
|
|
1348
|
-
return {
|
|
1349
|
-
id,
|
|
1350
|
-
text: str(row["text"]) ?? "",
|
|
1351
|
-
askerName: str(row["asker_name"]) ?? "",
|
|
1352
|
-
anonymous: row["anonymous"] === true,
|
|
1353
|
-
state: state === "answered" || state === "dismissed" ? state : "open",
|
|
1354
|
-
answer: str(row["answer"]),
|
|
1355
|
-
answeredByName: str(row["answered_by_name"]),
|
|
1356
|
-
upvotes: num(row["upvotes"]) ?? 0,
|
|
1357
|
-
upvotedByMe: row["upvoted_by_me"] === true,
|
|
1358
|
-
mine: row["mine"] === true,
|
|
1359
|
-
createdAt: str(row["created_at"])
|
|
1360
|
-
};
|
|
1361
|
-
}
|
|
1362
|
-
function strokeFromRow(row) {
|
|
1363
|
-
const id = str(row["id"]);
|
|
1364
|
-
if (id === null || !Array.isArray(row["points"])) return null;
|
|
1365
|
-
const points = [];
|
|
1366
|
-
for (const raw of row["points"]) {
|
|
1367
|
-
if (Array.isArray(raw) && typeof raw[0] === "number" && typeof raw[1] === "number") {
|
|
1368
|
-
points.push([raw[0], raw[1]]);
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
return {
|
|
1372
|
-
id,
|
|
1373
|
-
points,
|
|
1374
|
-
color: str(row["color"]) ?? "#111827",
|
|
1375
|
-
width: num(row["width"]) ?? 3,
|
|
1376
|
-
tool: row["tool"] === "highlighter" ? "highlighter" : "pen",
|
|
1377
|
-
by: str(row["by"]) ?? "",
|
|
1378
|
-
byName: str(row["by_name"]) ?? ""
|
|
1379
|
-
};
|
|
1380
|
-
}
|
|
1381
|
-
function broadcastFrom(value) {
|
|
1382
|
-
const row = obj(value);
|
|
1383
|
-
const text3 = row === null ? null : str(row["text"]);
|
|
1384
|
-
if (row === null || text3 === null) return null;
|
|
1385
|
-
return { text: text3, by: str(row["by"]) ?? "", at: str(row["at"]) ?? "" };
|
|
1386
|
-
}
|
|
1387
|
-
function planFromRow(row) {
|
|
1388
|
-
const id = str(row["id"]);
|
|
1389
|
-
if (id === null) return null;
|
|
1390
|
-
const rooms = [];
|
|
1391
|
-
for (const raw of Array.isArray(row["rooms"]) ? row["rooms"] : []) {
|
|
1392
|
-
const room = obj(raw);
|
|
1393
|
-
const roomId = room === null ? null : str(room["id"]);
|
|
1394
|
-
if (room === null || roomId === null) continue;
|
|
1395
|
-
rooms.push({ id: roomId, name: str(room["name"]) ?? roomId, identities: strings(room["identities"]) });
|
|
1396
|
-
}
|
|
1397
|
-
return {
|
|
1398
|
-
id,
|
|
1399
|
-
state: row["state"] === "open" ? "open" : "closed",
|
|
1400
|
-
rooms,
|
|
1401
|
-
allowChoose: row["allow_choose"] === true,
|
|
1402
|
-
minutes: num(row["minutes"]) ?? 0,
|
|
1403
|
-
openedAt: str(row["opened_at"]),
|
|
1404
|
-
endsAt: str(row["ends_at"]),
|
|
1405
|
-
closedAt: str(row["closed_at"]),
|
|
1406
|
-
broadcasts: (Array.isArray(row["broadcasts"]) ? row["broadcasts"] : []).map(broadcastFrom).filter((b) => b !== null)
|
|
1407
|
-
};
|
|
1408
|
-
}
|
|
1409
|
-
function settingsFromRow(row) {
|
|
1410
|
-
if (row === null) return null;
|
|
1411
|
-
return {
|
|
1412
|
-
pollsEnabled: row["polls_enabled"] === true,
|
|
1413
|
-
pollMaxOptions: num(row["poll_max_options"]) ?? 10,
|
|
1414
|
-
qaEnabled: row["qa_enabled"] === true,
|
|
1415
|
-
qaAnonymousAllowed: row["qa_anonymous_allowed"] === true,
|
|
1416
|
-
whiteboardEnabled: row["whiteboard_enabled"] === true,
|
|
1417
|
-
breakoutsEnabled: row["breakouts_enabled"] === true,
|
|
1418
|
-
breakoutMaxRooms: num(row["breakout_max_rooms"]) ?? 20,
|
|
1419
|
-
breakoutDefaultMinutes: num(row["breakout_default_minutes"]) ?? 15,
|
|
1420
|
-
captionTranslationEnabled: row["caption_translation_enabled"] === true,
|
|
1421
|
-
captionTranslationLanguage: str(row["caption_translation_language"]) ?? ""
|
|
1422
|
-
};
|
|
1423
|
-
}
|
|
1424
|
-
function collabFromState(body, previous) {
|
|
1425
|
-
const list = (key, parse) => (Array.isArray(body[key]) ? body[key] : []).map((raw) => {
|
|
1426
|
-
const row = obj(raw);
|
|
1427
|
-
return row === null ? null : parse(row);
|
|
1428
|
-
}).filter((item) => item !== null);
|
|
1429
|
-
const breakoutRow = obj(body["breakout"]);
|
|
1430
|
-
return {
|
|
1431
|
-
...previous,
|
|
1432
|
-
loaded: true,
|
|
1433
|
-
error: null,
|
|
1434
|
-
settings: settingsFromRow(obj(body["settings"])),
|
|
1435
|
-
polls: list("polls", pollFromRow),
|
|
1436
|
-
questions: list("questions", questionFromRow),
|
|
1437
|
-
strokes: list("strokes", strokeFromRow),
|
|
1438
|
-
breakout: breakoutRow === null ? null : planFromRow(breakoutRow)
|
|
1439
|
-
};
|
|
1440
|
-
}
|
|
1441
|
-
function upsert(items, next) {
|
|
1442
|
-
const index = items.findIndex((item) => item.id === next.id);
|
|
1443
|
-
if (index === -1) return [...items, next];
|
|
1444
|
-
const copy = items.slice();
|
|
1445
|
-
copy[index] = next;
|
|
1446
|
-
return copy;
|
|
1447
|
-
}
|
|
1448
|
-
function withItem(collab, row, fromRoom = false) {
|
|
1449
|
-
const kind = str(row["kind"]);
|
|
1450
|
-
if (kind === "poll") {
|
|
1451
|
-
const poll = pollFromRow(row);
|
|
1452
|
-
if (poll === null) return collab;
|
|
1453
|
-
const known = collab.polls.find((p) => p.id === poll.id);
|
|
1454
|
-
let merged = fromRoom && known !== void 0 ? { ...poll, myVote: known.myVote } : poll;
|
|
1455
|
-
if (fromRoom && known !== void 0 && !poll.options.some((o) => o.votes !== void 0)) {
|
|
1456
|
-
const counted = new Map(known.options.map((o) => [o.id, o]));
|
|
1457
|
-
merged = {
|
|
1458
|
-
...merged,
|
|
1459
|
-
voterCount: known.voterCount,
|
|
1460
|
-
options: merged.options.map((o) => {
|
|
1461
|
-
const had = counted.get(o.id);
|
|
1462
|
-
return had === void 0 ? o : { ...o, votes: had.votes, voters: had.voters };
|
|
1463
|
-
})
|
|
1464
|
-
};
|
|
1465
|
-
}
|
|
1466
|
-
return { ...collab, polls: upsert(collab.polls, merged) };
|
|
1467
|
-
}
|
|
1468
|
-
if (kind === "question") {
|
|
1469
|
-
const question = questionFromRow(row);
|
|
1470
|
-
if (question === null) return collab;
|
|
1471
|
-
const known = collab.questions.find((q) => q.id === question.id);
|
|
1472
|
-
const merged = fromRoom && known !== void 0 ? { ...question, mine: known.mine, upvotedByMe: known.upvotedByMe } : question;
|
|
1473
|
-
return { ...collab, questions: upsert(collab.questions, merged) };
|
|
1474
|
-
}
|
|
1475
|
-
if (kind === "stroke") {
|
|
1476
|
-
const stroke = strokeFromRow(row);
|
|
1477
|
-
if (stroke === null) return collab;
|
|
1478
|
-
return { ...collab, strokes: upsert(collab.strokes, stroke) };
|
|
1479
|
-
}
|
|
1480
|
-
if (kind === "breakout") {
|
|
1481
|
-
const plan = planFromRow(row);
|
|
1482
|
-
if (plan === null) return collab;
|
|
1483
|
-
return { ...collab, breakout: plan };
|
|
1484
|
-
}
|
|
1485
|
-
return collab;
|
|
1486
|
-
}
|
|
1487
|
-
function without(collab, ids) {
|
|
1488
|
-
const gone = new Set(ids);
|
|
1489
|
-
return {
|
|
1490
|
-
...collab,
|
|
1491
|
-
polls: collab.polls.filter((p) => !gone.has(p.id)),
|
|
1492
|
-
questions: collab.questions.filter((q) => !gone.has(q.id)),
|
|
1493
|
-
strokes: collab.strokes.filter((s) => !gone.has(s.id))
|
|
1494
|
-
};
|
|
1495
|
-
}
|
|
1496
|
-
function applyCollabPacket(collab, payload, context) {
|
|
1497
|
-
const item = obj(payload["item"]);
|
|
1498
|
-
if (item !== null) {
|
|
1499
|
-
const kind = str(item["kind"]);
|
|
1500
|
-
let next = withItem(collab, item, true);
|
|
1501
|
-
if (kind === "poll" && str(item["state"]) === "live") {
|
|
1502
|
-
const before = collab.polls.find((p) => p.id === str(item["id"]));
|
|
1503
|
-
if (before === void 0 || before.state !== "live") {
|
|
1504
|
-
next = { ...next, panelRequest: { panel: "polls", at: context.now } };
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
if (kind === "breakout") {
|
|
1508
|
-
const plan = planFromRow(item);
|
|
1509
|
-
if (plan !== null && plan.state === "closed") {
|
|
1510
|
-
next = { ...next, moveRequest: { roomId: null, at: context.now } };
|
|
1511
|
-
}
|
|
1512
|
-
}
|
|
1513
|
-
const move = obj(payload["move"]);
|
|
1514
|
-
if (move !== null && str(move["identity"]) === context.localIdentity) {
|
|
1515
|
-
next = { ...next, moveRequest: { roomId: str(move["room_id"]), at: context.now } };
|
|
1516
|
-
}
|
|
1517
|
-
return { next };
|
|
1518
|
-
}
|
|
1519
|
-
if (Array.isArray(payload["removed"])) {
|
|
1520
|
-
return { next: without(collab, strings(payload["removed"])) };
|
|
1521
|
-
}
|
|
1522
|
-
if (Array.isArray(payload["hidden"])) {
|
|
1523
|
-
return context.isHost ? { next: null, dropped: "hosts keep dismissed questions" } : { next: without(collab, strings(payload["hidden"])) };
|
|
1524
|
-
}
|
|
1525
|
-
if (payload["cleared"] === "whiteboard") {
|
|
1526
|
-
return { next: { ...collab, strokes: [] } };
|
|
1527
|
-
}
|
|
1528
|
-
const broadcast = broadcastFrom(payload["broadcast"]);
|
|
1529
|
-
if (broadcast !== null) {
|
|
1530
|
-
return { next: { ...collab, broadcast } };
|
|
1531
|
-
}
|
|
1532
|
-
return { next: null, dropped: "a collab packet with nothing this version understands" };
|
|
1533
|
-
}
|
|
1534
|
-
function assignedRoom(plan, identity) {
|
|
1535
|
-
if (plan === null || plan.state !== "open" || identity === null) return null;
|
|
1536
|
-
return plan.rooms.find((room) => room.identities.includes(identity)) ?? null;
|
|
1537
|
-
}
|
|
1538
|
-
function autoAssign(identities, rooms, exclude = []) {
|
|
1539
|
-
const count2 = Math.max(1, Math.floor(rooms));
|
|
1540
|
-
const out = Array.from({ length: count2 }, () => []);
|
|
1541
|
-
const skip = new Set(exclude);
|
|
1542
|
-
let index = 0;
|
|
1543
|
-
for (const identity of identities) {
|
|
1544
|
-
if (skip.has(identity)) continue;
|
|
1545
|
-
out[index % count2].push(identity);
|
|
1546
|
-
index += 1;
|
|
1547
|
-
}
|
|
1548
|
-
return out;
|
|
1549
|
-
}
|
|
1550
|
-
function breakoutRemainingMs(plan, now) {
|
|
1551
|
-
if (plan === null || plan.state !== "open" || plan.endsAt === null) return null;
|
|
1552
|
-
const end = Date.parse(plan.endsAt);
|
|
1553
|
-
return Number.isNaN(end) ? null : Math.max(0, end - now);
|
|
1554
|
-
}
|
|
1555
|
-
function defaultCaptionLanguage(settings, viewerLanguage) {
|
|
1556
|
-
const configured = settings?.captionTranslationLanguage.trim() ?? "";
|
|
1557
|
-
if (configured.length > 0) return configured;
|
|
1558
|
-
const own = (viewerLanguage ?? "").trim();
|
|
1559
|
-
return own.length > 0 ? own : "en";
|
|
1560
|
-
}
|
|
1561
|
-
var CAPTION_LANGUAGES = [
|
|
1562
|
-
{ tag: "en", name: "English" },
|
|
1563
|
-
{ tag: "es", name: "Spanish" },
|
|
1564
|
-
{ tag: "fr", name: "French" },
|
|
1565
|
-
{ tag: "de", name: "German" },
|
|
1566
|
-
{ tag: "it", name: "Italian" },
|
|
1567
|
-
{ tag: "pt", name: "Portuguese" },
|
|
1568
|
-
{ tag: "nl", name: "Dutch" },
|
|
1569
|
-
{ tag: "pl", name: "Polish" },
|
|
1570
|
-
{ tag: "ru", name: "Russian" },
|
|
1571
|
-
{ tag: "uk", name: "Ukrainian" },
|
|
1572
|
-
{ tag: "tr", name: "Turkish" },
|
|
1573
|
-
{ tag: "ar", name: "Arabic" },
|
|
1574
|
-
{ tag: "he", name: "Hebrew" },
|
|
1575
|
-
{ tag: "fa", name: "Persian" },
|
|
1576
|
-
{ tag: "hi", name: "Hindi" },
|
|
1577
|
-
{ tag: "bn", name: "Bengali" },
|
|
1578
|
-
{ tag: "zh", name: "Chinese" },
|
|
1579
|
-
{ tag: "ja", name: "Japanese" },
|
|
1580
|
-
{ tag: "ko", name: "Korean" },
|
|
1581
|
-
{ tag: "vi", name: "Vietnamese" },
|
|
1582
|
-
{ tag: "th", name: "Thai" },
|
|
1583
|
-
{ tag: "id", name: "Indonesian" },
|
|
1584
|
-
{ tag: "sv", name: "Swedish" }
|
|
1585
|
-
];
|
|
1586
|
-
async function loadMeetingActivities(api, meetingId, meetingPass = null) {
|
|
1587
|
-
let response;
|
|
1588
|
-
try {
|
|
1589
|
-
response = await api.request({
|
|
1590
|
-
path: `${MEET_ROUTES.collab}?meeting_id=${encodeURIComponent(meetingId)}`,
|
|
1591
|
-
method: "GET",
|
|
1592
|
-
operation: "meet.loadMeetingActivities",
|
|
1593
|
-
requireAuth: meetingPass === null,
|
|
1594
|
-
...meetingPass !== null ? { headers: { [MEETING_PASS_HEADER]: meetingPass } } : {}
|
|
1595
|
-
});
|
|
1596
|
-
} catch (error) {
|
|
1597
|
-
return {
|
|
1598
|
-
collab: null,
|
|
1599
|
-
refusal: {
|
|
1600
|
-
message: `Polls, questions and the whiteboard could not be read (${error.message}).`,
|
|
1601
|
-
remedy: error.remedy ?? "Reload the page."
|
|
1246
|
+
async accept(id, mode) {
|
|
1247
|
+
const held = incoming.get(id);
|
|
1248
|
+
if (held !== void 0 && !canTransition(held.state, "connecting")) {
|
|
1249
|
+
throw new MeetError(
|
|
1250
|
+
"conflict",
|
|
1251
|
+
`meet.calls.accept: this call is already ${held.state}`,
|
|
1252
|
+
"A late accept must not resurrect a settled call. Close the ringing UI; the caller has already moved on."
|
|
1253
|
+
);
|
|
1602
1254
|
}
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1255
|
+
const settled = await repository.settleCallInvite(id, "connecting", null);
|
|
1256
|
+
settleLocal(settled);
|
|
1257
|
+
channel?.send(MEET_EVENTS.settled, settled);
|
|
1258
|
+
to(settled.callerUserId).send(MEET_EVENTS.settled, { ...settled, mode });
|
|
1259
|
+
return settled;
|
|
1260
|
+
},
|
|
1261
|
+
async decline(id, message) {
|
|
1262
|
+
const settled = await repository.settleCallInvite(id, "declined", message ?? null);
|
|
1263
|
+
settleLocal(settled);
|
|
1264
|
+
channel?.send(MEET_EVENTS.settled, settled);
|
|
1265
|
+
to(settled.callerUserId).send(MEET_EVENTS.settled, settled);
|
|
1266
|
+
return settled;
|
|
1267
|
+
},
|
|
1268
|
+
async cancel(id) {
|
|
1269
|
+
const settled = await repository.settleCallInvite(id, "cancelled", null);
|
|
1270
|
+
clearRing(id);
|
|
1271
|
+
if (outgoing?.id === id) outgoing = settled;
|
|
1272
|
+
for (const callee of settled.calleeUserIds) {
|
|
1273
|
+
to(callee).send(MEET_EVENTS.cancel, settled);
|
|
1618
1274
|
}
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1275
|
+
return settled;
|
|
1276
|
+
},
|
|
1277
|
+
incoming: () => [...incoming.values()],
|
|
1278
|
+
outgoing: () => outgoing,
|
|
1279
|
+
ingest,
|
|
1280
|
+
dispose() {
|
|
1281
|
+
for (const id of [...timeouts.keys()]) clearRing(asCallId(id));
|
|
1282
|
+
incoming.clear();
|
|
1283
|
+
for (const handle of outbound.values()) handle.close();
|
|
1284
|
+
outbound.clear();
|
|
1285
|
+
channel?.close();
|
|
1286
|
+
channel = null;
|
|
1287
|
+
}
|
|
1288
|
+
};
|
|
1622
1289
|
}
|
|
1623
1290
|
|
|
1624
1291
|
// src/core/repository.ts
|
|
@@ -1813,7 +1480,7 @@ var OCCURRENCE_STATES = ["scheduled", "moved", "cancelled"];
|
|
|
1813
1480
|
function rsvpState(value) {
|
|
1814
1481
|
return RSVP_STATES.includes(value) ? value : "needs_action";
|
|
1815
1482
|
}
|
|
1816
|
-
function
|
|
1483
|
+
function num(row, key) {
|
|
1817
1484
|
const value = row[key];
|
|
1818
1485
|
return typeof value === "number" ? value : null;
|
|
1819
1486
|
}
|
|
@@ -1835,7 +1502,7 @@ function projectInvitee(row) {
|
|
|
1835
1502
|
rsvpState: rsvpState(text(row, "rsvp_state")),
|
|
1836
1503
|
respondedAt: when(row, "responded_at"),
|
|
1837
1504
|
rsvpNote: text(row, "rsvp_note"),
|
|
1838
|
-
lastSentSequence:
|
|
1505
|
+
lastSentSequence: num(row, "last_sent_sequence"),
|
|
1839
1506
|
lastSentAt: when(row, "last_sent_at")
|
|
1840
1507
|
};
|
|
1841
1508
|
}
|
|
@@ -1846,10 +1513,10 @@ function projectOccurrence(row) {
|
|
|
1846
1513
|
meetingId: asMeetingId(requireText(row, "meeting_id", operation)),
|
|
1847
1514
|
originalStart: when(row, "original_start") ?? requireText(row, "original_start", operation),
|
|
1848
1515
|
occurrenceStart: when(row, "occurrence_start") ?? requireText(row, "occurrence_start", operation),
|
|
1849
|
-
durationMinutes:
|
|
1516
|
+
durationMinutes: num(row, "duration_minutes"),
|
|
1850
1517
|
// An unknown state is shown as scheduled, never dropped: the row is real.
|
|
1851
1518
|
state: OCCURRENCE_STATES.includes(state) ? state : "scheduled",
|
|
1852
|
-
sequence:
|
|
1519
|
+
sequence: num(row, "sequence") ?? 0
|
|
1853
1520
|
};
|
|
1854
1521
|
}
|
|
1855
1522
|
function projectUpcoming(row) {
|
|
@@ -1878,9 +1545,9 @@ function projectOverride(row) {
|
|
|
1878
1545
|
originalStart: when(row, "original_start") ?? requireText(row, "original_start", operation),
|
|
1879
1546
|
state: text(row, "state") === "moved" ? "moved" : "cancelled",
|
|
1880
1547
|
newStart: when(row, "new_start"),
|
|
1881
|
-
newDurationMinutes:
|
|
1548
|
+
newDurationMinutes: num(row, "new_duration_minutes"),
|
|
1882
1549
|
reason: text(row, "reason"),
|
|
1883
|
-
calendarSequence:
|
|
1550
|
+
calendarSequence: num(row, "calendar_sequence") ?? 0,
|
|
1884
1551
|
deletedAt: when(row, "deleted_at")
|
|
1885
1552
|
};
|
|
1886
1553
|
}
|
|
@@ -1904,7 +1571,7 @@ function projectRsvpInvitation(body) {
|
|
|
1904
1571
|
title: text(meeting, "title") ?? "Meeting",
|
|
1905
1572
|
slug: requireText(meeting, "slug", operation),
|
|
1906
1573
|
scheduledFor: when(meeting, "scheduled_for"),
|
|
1907
|
-
durationMinutes:
|
|
1574
|
+
durationMinutes: num(meeting, "duration_minutes"),
|
|
1908
1575
|
timeZone: text(meeting, "time_zone") ?? "UTC",
|
|
1909
1576
|
agenda: text(meeting, "agenda"),
|
|
1910
1577
|
recurrenceRule: text(meeting, "recurrence_rule"),
|
|
@@ -2132,7 +1799,7 @@ function createMeetRepository(options) {
|
|
|
2132
1799
|
p_duration_minutes: input.durationMinutes ?? null,
|
|
2133
1800
|
p_agenda: input.agenda ?? null,
|
|
2134
1801
|
p_recurrence_rule: input.recurrenceRule ?? null,
|
|
2135
|
-
p_settings:
|
|
1802
|
+
p_settings: scheduleSettingsPatch(input.settings ?? {}, input.appPanel, input.observers)
|
|
2136
1803
|
})
|
|
2137
1804
|
);
|
|
2138
1805
|
return projectMeeting(row);
|
|
@@ -2467,74 +2134,447 @@ function createMeetRepository(options) {
|
|
|
2467
2134
|
}
|
|
2468
2135
|
};
|
|
2469
2136
|
}
|
|
2470
|
-
var LIBRARY_STATES = [
|
|
2471
|
-
"idle",
|
|
2472
|
-
"starting",
|
|
2473
|
-
"recording",
|
|
2474
|
-
"stopping",
|
|
2475
|
-
"processing",
|
|
2476
|
-
"available",
|
|
2477
|
-
"expired",
|
|
2478
|
-
"failed"
|
|
2479
|
-
];
|
|
2480
|
-
function projectLibraryRecording(row) {
|
|
2481
|
-
const operation = "meet.projectLibraryRecording";
|
|
2482
|
-
const state = text(row, "state");
|
|
2483
|
-
const role = text(row, "my_role");
|
|
2137
|
+
var LIBRARY_STATES = [
|
|
2138
|
+
"idle",
|
|
2139
|
+
"starting",
|
|
2140
|
+
"recording",
|
|
2141
|
+
"stopping",
|
|
2142
|
+
"processing",
|
|
2143
|
+
"available",
|
|
2144
|
+
"expired",
|
|
2145
|
+
"failed"
|
|
2146
|
+
];
|
|
2147
|
+
function projectLibraryRecording(row) {
|
|
2148
|
+
const operation = "meet.projectLibraryRecording";
|
|
2149
|
+
const state = text(row, "state");
|
|
2150
|
+
const role = text(row, "my_role");
|
|
2151
|
+
return {
|
|
2152
|
+
id: requireText(row, "recording_id", operation),
|
|
2153
|
+
meetingId: asMeetingId(requireText(row, "meeting_id", operation)),
|
|
2154
|
+
meetingTitle: text(row, "meeting_title") ?? "Meeting",
|
|
2155
|
+
meetingSlug: requireText(row, "meeting_slug", operation),
|
|
2156
|
+
role: role === "host" || role === "cohost" || role === "invitee" ? role : "attendee",
|
|
2157
|
+
state: LIBRARY_STATES.includes(state) ? state : "failed",
|
|
2158
|
+
title: text(row, "recording_title"),
|
|
2159
|
+
fileId: text(row, "file_id"),
|
|
2160
|
+
startedAt: text(row, "started_at"),
|
|
2161
|
+
endedAt: text(row, "ended_at"),
|
|
2162
|
+
durationMs: num(row, "duration_ms"),
|
|
2163
|
+
sizeBytes: num(row, "size_bytes"),
|
|
2164
|
+
failureReason: text(row, "failure_reason"),
|
|
2165
|
+
archivedAt: text(row, "deleted_at"),
|
|
2166
|
+
organizationId: asOrganizationId(requireText(row, "organization_id", operation))
|
|
2167
|
+
};
|
|
2168
|
+
}
|
|
2169
|
+
var SEARCH_SOURCES = [
|
|
2170
|
+
"title",
|
|
2171
|
+
"summary",
|
|
2172
|
+
"decision",
|
|
2173
|
+
"action_item",
|
|
2174
|
+
"note",
|
|
2175
|
+
"transcript"
|
|
2176
|
+
];
|
|
2177
|
+
function projectSearchHit(row) {
|
|
2178
|
+
const operation = "meet.projectSearchHit";
|
|
2179
|
+
const source = text(row, "source");
|
|
2180
|
+
return {
|
|
2181
|
+
meetingId: asMeetingId(requireText(row, "meeting_id", operation)),
|
|
2182
|
+
meetingTitle: text(row, "meeting_title") ?? "Meeting",
|
|
2183
|
+
meetingSlug: requireText(row, "meeting_slug", operation),
|
|
2184
|
+
meetingAt: text(row, "meeting_at"),
|
|
2185
|
+
source: SEARCH_SOURCES.includes(source) ? source : "note",
|
|
2186
|
+
refId: requireText(row, "ref_id", operation),
|
|
2187
|
+
speaker: text(row, "speaker"),
|
|
2188
|
+
snippet: text(row, "snippet") ?? "",
|
|
2189
|
+
at: text(row, "said_at"),
|
|
2190
|
+
rank: num(row, "rank") ?? 0
|
|
2191
|
+
};
|
|
2192
|
+
}
|
|
2193
|
+
function snippetRuns(snippet) {
|
|
2194
|
+
const runs = [];
|
|
2195
|
+
const pattern = /⟦([^⟧]*)⟧/g;
|
|
2196
|
+
let last = 0;
|
|
2197
|
+
for (const match of snippet.matchAll(pattern)) {
|
|
2198
|
+
const start = match.index ?? 0;
|
|
2199
|
+
if (start > last) runs.push({ text: snippet.slice(last, start), hit: false });
|
|
2200
|
+
runs.push({ text: match[1] ?? "", hit: true });
|
|
2201
|
+
last = start + match[0].length;
|
|
2202
|
+
}
|
|
2203
|
+
if (last < snippet.length) runs.push({ text: snippet.slice(last), hit: false });
|
|
2204
|
+
return runs;
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
// src/core/app-panel.ts
|
|
2208
|
+
function appPanelOf(meeting) {
|
|
2209
|
+
const raw = meeting?.metadata?.["app_panel"];
|
|
2210
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null;
|
|
2211
|
+
const key = raw["key"];
|
|
2212
|
+
const recordId = raw["record_id"];
|
|
2213
|
+
if (typeof key !== "string" || key.length === 0) return null;
|
|
2214
|
+
if (typeof recordId !== "string" || recordId.length === 0) return null;
|
|
2215
|
+
return { key, recordId };
|
|
2216
|
+
}
|
|
2217
|
+
function scheduleSettingsPatch(settings, appPanel, observers) {
|
|
2218
|
+
const patch = settingsPatch(settings);
|
|
2219
|
+
if (appPanel !== void 0) patch["app_panel"] = { key: appPanel.key, record_id: appPanel.recordId };
|
|
2220
|
+
if (observers !== void 0 && observers.length > 0) patch["observers"] = [...observers];
|
|
2221
|
+
return patch;
|
|
2222
|
+
}
|
|
2223
|
+
function focusFromRow(value) {
|
|
2224
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
2225
|
+
const row = value;
|
|
2226
|
+
if (typeof row["panel"] !== "string") return null;
|
|
2227
|
+
return {
|
|
2228
|
+
panel: row["panel"],
|
|
2229
|
+
section: typeof row["section"] === "string" ? row["section"] : "",
|
|
2230
|
+
byName: typeof row["by_name"] === "string" ? row["by_name"] : "",
|
|
2231
|
+
at: typeof row["at"] === "string" ? row["at"] : ""
|
|
2232
|
+
};
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
// src/core/collab.ts
|
|
2236
|
+
var EMPTY_COLLAB = {
|
|
2237
|
+
loaded: false,
|
|
2238
|
+
error: null,
|
|
2239
|
+
settings: null,
|
|
2240
|
+
polls: [],
|
|
2241
|
+
questions: [],
|
|
2242
|
+
strokes: [],
|
|
2243
|
+
breakout: null,
|
|
2244
|
+
broadcast: null,
|
|
2245
|
+
moveRequest: null,
|
|
2246
|
+
panelRequest: null,
|
|
2247
|
+
captionLanguage: null,
|
|
2248
|
+
captionTranslations: {},
|
|
2249
|
+
captionTranslationError: null,
|
|
2250
|
+
focus: null
|
|
2251
|
+
};
|
|
2252
|
+
function obj(value) {
|
|
2253
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
2254
|
+
}
|
|
2255
|
+
function str(value) {
|
|
2256
|
+
return typeof value === "string" ? value : null;
|
|
2257
|
+
}
|
|
2258
|
+
function num2(value) {
|
|
2259
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
2260
|
+
}
|
|
2261
|
+
function strings(value) {
|
|
2262
|
+
return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
2263
|
+
}
|
|
2264
|
+
function pollFromRow(row) {
|
|
2265
|
+
const id = str(row["id"]);
|
|
2266
|
+
if (id === null) return null;
|
|
2267
|
+
const options = [];
|
|
2268
|
+
for (const raw of Array.isArray(row["options"]) ? row["options"] : []) {
|
|
2269
|
+
const option = obj(raw);
|
|
2270
|
+
const optionId = option === null ? null : str(option["id"]);
|
|
2271
|
+
if (option === null || optionId === null) continue;
|
|
2272
|
+
const votes = num2(option["votes"]);
|
|
2273
|
+
options.push({
|
|
2274
|
+
id: optionId,
|
|
2275
|
+
text: str(option["text"]) ?? "",
|
|
2276
|
+
...votes !== null ? { votes } : {},
|
|
2277
|
+
...Array.isArray(option["voters"]) ? { voters: strings(option["voters"]) } : {}
|
|
2278
|
+
});
|
|
2279
|
+
}
|
|
2280
|
+
const state = str(row["state"]);
|
|
2281
|
+
return {
|
|
2282
|
+
id,
|
|
2283
|
+
question: str(row["question"]) ?? "",
|
|
2284
|
+
options,
|
|
2285
|
+
multiple: row["multiple"] === true,
|
|
2286
|
+
anonymous: row["anonymous"] === true,
|
|
2287
|
+
state: state === "live" || state === "closed" ? state : "draft",
|
|
2288
|
+
resultsShared: row["results_shared"] === true,
|
|
2289
|
+
voterCount: num2(row["voter_count"]),
|
|
2290
|
+
myVote: strings(row["my_vote"]),
|
|
2291
|
+
createdByName: str(row["created_by_name"]) ?? "",
|
|
2292
|
+
createdAt: str(row["created_at"])
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
function questionFromRow(row) {
|
|
2296
|
+
const id = str(row["id"]);
|
|
2297
|
+
if (id === null) return null;
|
|
2298
|
+
const state = str(row["state"]);
|
|
2299
|
+
return {
|
|
2300
|
+
id,
|
|
2301
|
+
text: str(row["text"]) ?? "",
|
|
2302
|
+
askerName: str(row["asker_name"]) ?? "",
|
|
2303
|
+
anonymous: row["anonymous"] === true,
|
|
2304
|
+
state: state === "answered" || state === "dismissed" ? state : "open",
|
|
2305
|
+
answer: str(row["answer"]),
|
|
2306
|
+
answeredByName: str(row["answered_by_name"]),
|
|
2307
|
+
upvotes: num2(row["upvotes"]) ?? 0,
|
|
2308
|
+
upvotedByMe: row["upvoted_by_me"] === true,
|
|
2309
|
+
mine: row["mine"] === true,
|
|
2310
|
+
createdAt: str(row["created_at"])
|
|
2311
|
+
};
|
|
2312
|
+
}
|
|
2313
|
+
function strokeFromRow(row) {
|
|
2314
|
+
const id = str(row["id"]);
|
|
2315
|
+
if (id === null || !Array.isArray(row["points"])) return null;
|
|
2316
|
+
const points = [];
|
|
2317
|
+
for (const raw of row["points"]) {
|
|
2318
|
+
if (Array.isArray(raw) && typeof raw[0] === "number" && typeof raw[1] === "number") {
|
|
2319
|
+
points.push([raw[0], raw[1]]);
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
return {
|
|
2323
|
+
id,
|
|
2324
|
+
points,
|
|
2325
|
+
color: str(row["color"]) ?? "#111827",
|
|
2326
|
+
width: num2(row["width"]) ?? 3,
|
|
2327
|
+
tool: row["tool"] === "highlighter" ? "highlighter" : "pen",
|
|
2328
|
+
by: str(row["by"]) ?? "",
|
|
2329
|
+
byName: str(row["by_name"]) ?? ""
|
|
2330
|
+
};
|
|
2331
|
+
}
|
|
2332
|
+
function broadcastFrom(value) {
|
|
2333
|
+
const row = obj(value);
|
|
2334
|
+
const text3 = row === null ? null : str(row["text"]);
|
|
2335
|
+
if (row === null || text3 === null) return null;
|
|
2336
|
+
return { text: text3, by: str(row["by"]) ?? "", at: str(row["at"]) ?? "" };
|
|
2337
|
+
}
|
|
2338
|
+
function planFromRow(row) {
|
|
2339
|
+
const id = str(row["id"]);
|
|
2340
|
+
if (id === null) return null;
|
|
2341
|
+
const rooms = [];
|
|
2342
|
+
for (const raw of Array.isArray(row["rooms"]) ? row["rooms"] : []) {
|
|
2343
|
+
const room = obj(raw);
|
|
2344
|
+
const roomId = room === null ? null : str(room["id"]);
|
|
2345
|
+
if (room === null || roomId === null) continue;
|
|
2346
|
+
rooms.push({ id: roomId, name: str(room["name"]) ?? roomId, identities: strings(room["identities"]) });
|
|
2347
|
+
}
|
|
2348
|
+
return {
|
|
2349
|
+
id,
|
|
2350
|
+
state: row["state"] === "open" ? "open" : "closed",
|
|
2351
|
+
rooms,
|
|
2352
|
+
allowChoose: row["allow_choose"] === true,
|
|
2353
|
+
minutes: num2(row["minutes"]) ?? 0,
|
|
2354
|
+
openedAt: str(row["opened_at"]),
|
|
2355
|
+
endsAt: str(row["ends_at"]),
|
|
2356
|
+
closedAt: str(row["closed_at"]),
|
|
2357
|
+
broadcasts: (Array.isArray(row["broadcasts"]) ? row["broadcasts"] : []).map(broadcastFrom).filter((b) => b !== null)
|
|
2358
|
+
};
|
|
2359
|
+
}
|
|
2360
|
+
function settingsFromRow(row) {
|
|
2361
|
+
if (row === null) return null;
|
|
2362
|
+
return {
|
|
2363
|
+
pollsEnabled: row["polls_enabled"] === true,
|
|
2364
|
+
pollMaxOptions: num2(row["poll_max_options"]) ?? 10,
|
|
2365
|
+
qaEnabled: row["qa_enabled"] === true,
|
|
2366
|
+
qaAnonymousAllowed: row["qa_anonymous_allowed"] === true,
|
|
2367
|
+
whiteboardEnabled: row["whiteboard_enabled"] === true,
|
|
2368
|
+
breakoutsEnabled: row["breakouts_enabled"] === true,
|
|
2369
|
+
breakoutMaxRooms: num2(row["breakout_max_rooms"]) ?? 20,
|
|
2370
|
+
breakoutDefaultMinutes: num2(row["breakout_default_minutes"]) ?? 15,
|
|
2371
|
+
captionTranslationEnabled: row["caption_translation_enabled"] === true,
|
|
2372
|
+
captionTranslationLanguage: str(row["caption_translation_language"]) ?? ""
|
|
2373
|
+
};
|
|
2374
|
+
}
|
|
2375
|
+
function collabFromState(body, previous) {
|
|
2376
|
+
const list = (key, parse) => (Array.isArray(body[key]) ? body[key] : []).map((raw) => {
|
|
2377
|
+
const row = obj(raw);
|
|
2378
|
+
return row === null ? null : parse(row);
|
|
2379
|
+
}).filter((item) => item !== null);
|
|
2380
|
+
const breakoutRow = obj(body["breakout"]);
|
|
2484
2381
|
return {
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
endedAt: text(row, "ended_at"),
|
|
2495
|
-
durationMs: num2(row, "duration_ms"),
|
|
2496
|
-
sizeBytes: num2(row, "size_bytes"),
|
|
2497
|
-
failureReason: text(row, "failure_reason"),
|
|
2498
|
-
archivedAt: text(row, "deleted_at"),
|
|
2499
|
-
organizationId: asOrganizationId(requireText(row, "organization_id", operation))
|
|
2382
|
+
...previous,
|
|
2383
|
+
loaded: true,
|
|
2384
|
+
error: null,
|
|
2385
|
+
settings: settingsFromRow(obj(body["settings"])),
|
|
2386
|
+
polls: list("polls", pollFromRow),
|
|
2387
|
+
questions: list("questions", questionFromRow),
|
|
2388
|
+
strokes: list("strokes", strokeFromRow),
|
|
2389
|
+
breakout: breakoutRow === null ? null : planFromRow(breakoutRow),
|
|
2390
|
+
focus: focusFromRow(body["focus"])
|
|
2500
2391
|
};
|
|
2501
2392
|
}
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2393
|
+
function upsert(items, next) {
|
|
2394
|
+
const index = items.findIndex((item) => item.id === next.id);
|
|
2395
|
+
if (index === -1) return [...items, next];
|
|
2396
|
+
const copy = items.slice();
|
|
2397
|
+
copy[index] = next;
|
|
2398
|
+
return copy;
|
|
2399
|
+
}
|
|
2400
|
+
function withItem(collab, row, fromRoom = false) {
|
|
2401
|
+
const kind = str(row["kind"]);
|
|
2402
|
+
if (kind === "poll") {
|
|
2403
|
+
const poll = pollFromRow(row);
|
|
2404
|
+
if (poll === null) return collab;
|
|
2405
|
+
const known = collab.polls.find((p) => p.id === poll.id);
|
|
2406
|
+
let merged = fromRoom && known !== void 0 ? { ...poll, myVote: known.myVote } : poll;
|
|
2407
|
+
if (fromRoom && known !== void 0 && !poll.options.some((o) => o.votes !== void 0)) {
|
|
2408
|
+
const counted = new Map(known.options.map((o) => [o.id, o]));
|
|
2409
|
+
merged = {
|
|
2410
|
+
...merged,
|
|
2411
|
+
voterCount: known.voterCount,
|
|
2412
|
+
options: merged.options.map((o) => {
|
|
2413
|
+
const had = counted.get(o.id);
|
|
2414
|
+
return had === void 0 ? o : { ...o, votes: had.votes, voters: had.voters };
|
|
2415
|
+
})
|
|
2416
|
+
};
|
|
2417
|
+
}
|
|
2418
|
+
return { ...collab, polls: upsert(collab.polls, merged) };
|
|
2419
|
+
}
|
|
2420
|
+
if (kind === "question") {
|
|
2421
|
+
const question = questionFromRow(row);
|
|
2422
|
+
if (question === null) return collab;
|
|
2423
|
+
const known = collab.questions.find((q) => q.id === question.id);
|
|
2424
|
+
const merged = fromRoom && known !== void 0 ? { ...question, mine: known.mine, upvotedByMe: known.upvotedByMe } : question;
|
|
2425
|
+
return { ...collab, questions: upsert(collab.questions, merged) };
|
|
2426
|
+
}
|
|
2427
|
+
if (kind === "stroke") {
|
|
2428
|
+
const stroke = strokeFromRow(row);
|
|
2429
|
+
if (stroke === null) return collab;
|
|
2430
|
+
return { ...collab, strokes: upsert(collab.strokes, stroke) };
|
|
2431
|
+
}
|
|
2432
|
+
if (kind === "breakout") {
|
|
2433
|
+
const plan = planFromRow(row);
|
|
2434
|
+
if (plan === null) return collab;
|
|
2435
|
+
return { ...collab, breakout: plan };
|
|
2436
|
+
}
|
|
2437
|
+
return collab;
|
|
2438
|
+
}
|
|
2439
|
+
function without(collab, ids) {
|
|
2440
|
+
const gone = new Set(ids);
|
|
2513
2441
|
return {
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
source: SEARCH_SOURCES.includes(source) ? source : "note",
|
|
2519
|
-
refId: requireText(row, "ref_id", operation),
|
|
2520
|
-
speaker: text(row, "speaker"),
|
|
2521
|
-
snippet: text(row, "snippet") ?? "",
|
|
2522
|
-
at: text(row, "said_at"),
|
|
2523
|
-
rank: num2(row, "rank") ?? 0
|
|
2442
|
+
...collab,
|
|
2443
|
+
polls: collab.polls.filter((p) => !gone.has(p.id)),
|
|
2444
|
+
questions: collab.questions.filter((q) => !gone.has(q.id)),
|
|
2445
|
+
strokes: collab.strokes.filter((s) => !gone.has(s.id))
|
|
2524
2446
|
};
|
|
2525
2447
|
}
|
|
2526
|
-
function
|
|
2527
|
-
const
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2448
|
+
function applyCollabPacket(collab, payload, context) {
|
|
2449
|
+
const item = obj(payload["item"]);
|
|
2450
|
+
if (item !== null) {
|
|
2451
|
+
const kind = str(item["kind"]);
|
|
2452
|
+
let next = withItem(collab, item, true);
|
|
2453
|
+
if (kind === "poll" && str(item["state"]) === "live") {
|
|
2454
|
+
const before = collab.polls.find((p) => p.id === str(item["id"]));
|
|
2455
|
+
if (before === void 0 || before.state !== "live") {
|
|
2456
|
+
next = { ...next, panelRequest: { panel: "polls", at: context.now } };
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
if (kind === "breakout") {
|
|
2460
|
+
const plan = planFromRow(item);
|
|
2461
|
+
if (plan !== null && plan.state === "closed") {
|
|
2462
|
+
next = { ...next, moveRequest: { roomId: null, at: context.now } };
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
const move = obj(payload["move"]);
|
|
2466
|
+
if (move !== null && str(move["identity"]) === context.localIdentity) {
|
|
2467
|
+
next = { ...next, moveRequest: { roomId: str(move["room_id"]), at: context.now } };
|
|
2468
|
+
}
|
|
2469
|
+
return { next };
|
|
2535
2470
|
}
|
|
2536
|
-
if (
|
|
2537
|
-
|
|
2471
|
+
if (payload["focus"] !== void 0) {
|
|
2472
|
+
const focus = focusFromRow(payload["focus"]);
|
|
2473
|
+
return focus === null ? { next: null, dropped: "a focus packet without a panel" } : { next: { ...collab, focus } };
|
|
2474
|
+
}
|
|
2475
|
+
if (Array.isArray(payload["removed"])) {
|
|
2476
|
+
return { next: without(collab, strings(payload["removed"])) };
|
|
2477
|
+
}
|
|
2478
|
+
if (Array.isArray(payload["hidden"])) {
|
|
2479
|
+
return context.isHost ? { next: null, dropped: "hosts keep dismissed questions" } : { next: without(collab, strings(payload["hidden"])) };
|
|
2480
|
+
}
|
|
2481
|
+
if (payload["cleared"] === "whiteboard") {
|
|
2482
|
+
return { next: { ...collab, strokes: [] } };
|
|
2483
|
+
}
|
|
2484
|
+
const broadcast = broadcastFrom(payload["broadcast"]);
|
|
2485
|
+
if (broadcast !== null) {
|
|
2486
|
+
return { next: { ...collab, broadcast } };
|
|
2487
|
+
}
|
|
2488
|
+
return { next: null, dropped: "a collab packet with nothing this version understands" };
|
|
2489
|
+
}
|
|
2490
|
+
function assignedRoom(plan, identity) {
|
|
2491
|
+
if (plan === null || plan.state !== "open" || identity === null) return null;
|
|
2492
|
+
return plan.rooms.find((room) => room.identities.includes(identity)) ?? null;
|
|
2493
|
+
}
|
|
2494
|
+
function autoAssign(identities, rooms, exclude = []) {
|
|
2495
|
+
const count2 = Math.max(1, Math.floor(rooms));
|
|
2496
|
+
const out = Array.from({ length: count2 }, () => []);
|
|
2497
|
+
const skip = new Set(exclude);
|
|
2498
|
+
let index = 0;
|
|
2499
|
+
for (const identity of identities) {
|
|
2500
|
+
if (skip.has(identity)) continue;
|
|
2501
|
+
out[index % count2].push(identity);
|
|
2502
|
+
index += 1;
|
|
2503
|
+
}
|
|
2504
|
+
return out;
|
|
2505
|
+
}
|
|
2506
|
+
function breakoutRemainingMs(plan, now) {
|
|
2507
|
+
if (plan === null || plan.state !== "open" || plan.endsAt === null) return null;
|
|
2508
|
+
const end = Date.parse(plan.endsAt);
|
|
2509
|
+
return Number.isNaN(end) ? null : Math.max(0, end - now);
|
|
2510
|
+
}
|
|
2511
|
+
function defaultCaptionLanguage(settings, viewerLanguage) {
|
|
2512
|
+
const configured = settings?.captionTranslationLanguage.trim() ?? "";
|
|
2513
|
+
if (configured.length > 0) return configured;
|
|
2514
|
+
const own = (viewerLanguage ?? "").trim();
|
|
2515
|
+
return own.length > 0 ? own : "en";
|
|
2516
|
+
}
|
|
2517
|
+
var CAPTION_LANGUAGES = [
|
|
2518
|
+
{ tag: "en", name: "English" },
|
|
2519
|
+
{ tag: "es", name: "Spanish" },
|
|
2520
|
+
{ tag: "fr", name: "French" },
|
|
2521
|
+
{ tag: "de", name: "German" },
|
|
2522
|
+
{ tag: "it", name: "Italian" },
|
|
2523
|
+
{ tag: "pt", name: "Portuguese" },
|
|
2524
|
+
{ tag: "nl", name: "Dutch" },
|
|
2525
|
+
{ tag: "pl", name: "Polish" },
|
|
2526
|
+
{ tag: "ru", name: "Russian" },
|
|
2527
|
+
{ tag: "uk", name: "Ukrainian" },
|
|
2528
|
+
{ tag: "tr", name: "Turkish" },
|
|
2529
|
+
{ tag: "ar", name: "Arabic" },
|
|
2530
|
+
{ tag: "he", name: "Hebrew" },
|
|
2531
|
+
{ tag: "fa", name: "Persian" },
|
|
2532
|
+
{ tag: "hi", name: "Hindi" },
|
|
2533
|
+
{ tag: "bn", name: "Bengali" },
|
|
2534
|
+
{ tag: "zh", name: "Chinese" },
|
|
2535
|
+
{ tag: "ja", name: "Japanese" },
|
|
2536
|
+
{ tag: "ko", name: "Korean" },
|
|
2537
|
+
{ tag: "vi", name: "Vietnamese" },
|
|
2538
|
+
{ tag: "th", name: "Thai" },
|
|
2539
|
+
{ tag: "id", name: "Indonesian" },
|
|
2540
|
+
{ tag: "sv", name: "Swedish" }
|
|
2541
|
+
];
|
|
2542
|
+
async function loadMeetingActivities(api, meetingId, meetingPass = null) {
|
|
2543
|
+
let response;
|
|
2544
|
+
try {
|
|
2545
|
+
response = await api.request({
|
|
2546
|
+
path: `${MEET_ROUTES.collab}?meeting_id=${encodeURIComponent(meetingId)}`,
|
|
2547
|
+
method: "GET",
|
|
2548
|
+
operation: "meet.loadMeetingActivities",
|
|
2549
|
+
requireAuth: meetingPass === null,
|
|
2550
|
+
...meetingPass !== null ? { headers: { [MEETING_PASS_HEADER]: meetingPass } } : {}
|
|
2551
|
+
});
|
|
2552
|
+
} catch (error) {
|
|
2553
|
+
return {
|
|
2554
|
+
collab: null,
|
|
2555
|
+
refusal: {
|
|
2556
|
+
message: `Polls, questions and the whiteboard could not be read (${error.message}).`,
|
|
2557
|
+
remedy: error.remedy ?? "Reload the page."
|
|
2558
|
+
}
|
|
2559
|
+
};
|
|
2560
|
+
}
|
|
2561
|
+
if (!response.ok) {
|
|
2562
|
+
let body = null;
|
|
2563
|
+
try {
|
|
2564
|
+
body = await response.json();
|
|
2565
|
+
} catch {
|
|
2566
|
+
body = null;
|
|
2567
|
+
}
|
|
2568
|
+
const said = readServerRefusal(body);
|
|
2569
|
+
return {
|
|
2570
|
+
collab: null,
|
|
2571
|
+
refusal: {
|
|
2572
|
+
message: said?.reason ?? `Polls and questions could not be read (the server answered ${response.status}).`,
|
|
2573
|
+
remedy: said?.remedy || "Reload the page."
|
|
2574
|
+
}
|
|
2575
|
+
};
|
|
2576
|
+
}
|
|
2577
|
+
return { collab: collabFromState(await response.json(), EMPTY_COLLAB), refusal: null };
|
|
2538
2578
|
}
|
|
2539
2579
|
|
|
2540
2580
|
// src/core/names.ts
|
|
@@ -3607,7 +3647,10 @@ function orderParticipants(participants, activeSpeakers) {
|
|
|
3607
3647
|
}
|
|
3608
3648
|
function computeStage(args) {
|
|
3609
3649
|
const pageSize = Math.max(1, args.pageSize ?? DEFAULT_PAGE_SIZE);
|
|
3610
|
-
const ordered = orderParticipants(
|
|
3650
|
+
const ordered = orderParticipants(
|
|
3651
|
+
args.participants.filter((participant) => !isObserverRole(participant.role)),
|
|
3652
|
+
args.activeSpeakers
|
|
3653
|
+
);
|
|
3611
3654
|
const sharer = ordered.find((participant) => participant.screenSharing) ?? null;
|
|
3612
3655
|
const pinnedParticipant = args.pinned === null ? null : ordered.find((participant) => participant.identity === args.pinned) ?? null;
|
|
3613
3656
|
const spotlit = args.spotlight == null ? null : ordered.find((participant) => participant.identity === args.spotlight) ?? null;
|
|
@@ -5383,7 +5426,8 @@ function createRoomEngine(options) {
|
|
|
5383
5426
|
identity,
|
|
5384
5427
|
...request.meetingId !== void 0 ? { meetingId: request.meetingId } : {},
|
|
5385
5428
|
...request.slug !== void 0 ? { slug: request.slug } : {},
|
|
5386
|
-
...request.breakoutRoomId != null ? { breakoutRoomId: request.breakoutRoomId } : {}
|
|
5429
|
+
...request.breakoutRoomId != null ? { breakoutRoomId: request.breakoutRoomId } : {},
|
|
5430
|
+
...request.observe === true ? { observe: true } : {}
|
|
5387
5431
|
});
|
|
5388
5432
|
current = token;
|
|
5389
5433
|
store.patch({
|
|
@@ -5394,7 +5438,8 @@ function createRoomEngine(options) {
|
|
|
5394
5438
|
standing: token.standing,
|
|
5395
5439
|
canRecord: token.canRecord,
|
|
5396
5440
|
canPublish: token.canPublish,
|
|
5397
|
-
canSubscribe: token.canSubscribe
|
|
5441
|
+
canSubscribe: token.canSubscribe,
|
|
5442
|
+
observersVisibleTo: token.observersVisibleTo ?? "everyone"
|
|
5398
5443
|
}
|
|
5399
5444
|
});
|
|
5400
5445
|
if (token.lobby || !token.canSubscribe) {
|
|
@@ -5894,7 +5939,9 @@ function createInRoomClient(options) {
|
|
|
5894
5939
|
...request.allowChoose !== void 0 ? { allow_choose: request.allowChoose } : {},
|
|
5895
5940
|
...request.minutes !== void 0 ? { minutes: request.minutes } : {},
|
|
5896
5941
|
...request.identity !== void 0 ? { identity: request.identity } : {},
|
|
5897
|
-
...request.roomId !== void 0 ? { room_id: request.roomId } : {}
|
|
5942
|
+
...request.roomId !== void 0 ? { room_id: request.roomId } : {},
|
|
5943
|
+
...request.panel !== void 0 ? { panel: request.panel } : {},
|
|
5944
|
+
...request.section !== void 0 ? { section: request.section } : {}
|
|
5898
5945
|
},
|
|
5899
5946
|
...hdrs !== void 0 ? { headers: hdrs } : {}
|
|
5900
5947
|
});
|
|
@@ -6837,6 +6884,7 @@ export {
|
|
|
6837
6884
|
activeWrapUpSummary,
|
|
6838
6885
|
activityAttention,
|
|
6839
6886
|
announceMeeting,
|
|
6887
|
+
appPanelOf,
|
|
6840
6888
|
applyCollabPacket,
|
|
6841
6889
|
applyRoomEvent,
|
|
6842
6890
|
asCallId,
|
|
@@ -6888,6 +6936,7 @@ export {
|
|
|
6888
6936
|
defaultCaptionLanguage,
|
|
6889
6937
|
displayNameFor,
|
|
6890
6938
|
fileDownloadPath,
|
|
6939
|
+
focusFromRow,
|
|
6891
6940
|
gridColumns,
|
|
6892
6941
|
groupTranscript,
|
|
6893
6942
|
guestRecordAccessExplanation,
|
|
@@ -6902,6 +6951,7 @@ export {
|
|
|
6902
6951
|
isLinkFollower,
|
|
6903
6952
|
isListenOnly,
|
|
6904
6953
|
isNoteTaker,
|
|
6954
|
+
isObserverRole,
|
|
6905
6955
|
isRealName,
|
|
6906
6956
|
isRoomEventTopic,
|
|
6907
6957
|
learnName,
|
|
@@ -6966,6 +7016,7 @@ export {
|
|
|
6966
7016
|
roleOf,
|
|
6967
7017
|
roomTopic,
|
|
6968
7018
|
rootAttributes,
|
|
7019
|
+
scheduleSettingsPatch,
|
|
6969
7020
|
searchTranscript,
|
|
6970
7021
|
sendFollowUp,
|
|
6971
7022
|
setCaptionLanguage,
|