@ai-matrx/meet 0.10.0 → 0.10.2
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 +12 -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 +4 -4
package/dist/core.cjs
CHANGED
|
@@ -80,6 +80,7 @@ __export(core_exports, {
|
|
|
80
80
|
activeWrapUpSummary: () => activeWrapUpSummary,
|
|
81
81
|
activityAttention: () => activityAttention,
|
|
82
82
|
announceMeeting: () => announceMeeting,
|
|
83
|
+
appPanelOf: () => appPanelOf,
|
|
83
84
|
applyCollabPacket: () => applyCollabPacket,
|
|
84
85
|
applyRoomEvent: () => applyRoomEvent,
|
|
85
86
|
asCallId: () => asCallId,
|
|
@@ -131,6 +132,7 @@ __export(core_exports, {
|
|
|
131
132
|
defaultCaptionLanguage: () => defaultCaptionLanguage,
|
|
132
133
|
displayNameFor: () => displayNameFor,
|
|
133
134
|
fileDownloadPath: () => fileDownloadPath,
|
|
135
|
+
focusFromRow: () => focusFromRow,
|
|
134
136
|
gridColumns: () => gridColumns,
|
|
135
137
|
groupTranscript: () => groupTranscript,
|
|
136
138
|
guestRecordAccessExplanation: () => guestRecordAccessExplanation,
|
|
@@ -145,6 +147,7 @@ __export(core_exports, {
|
|
|
145
147
|
isLinkFollower: () => isLinkFollower,
|
|
146
148
|
isListenOnly: () => isListenOnly,
|
|
147
149
|
isNoteTaker: () => isNoteTaker,
|
|
150
|
+
isObserverRole: () => isObserverRole,
|
|
148
151
|
isRealName: () => isRealName,
|
|
149
152
|
isRoomEventTopic: () => isRoomEventTopic,
|
|
150
153
|
learnName: () => learnName,
|
|
@@ -209,6 +212,7 @@ __export(core_exports, {
|
|
|
209
212
|
roleOf: () => roleOf,
|
|
210
213
|
roomTopic: () => roomTopic,
|
|
211
214
|
rootAttributes: () => rootAttributes,
|
|
215
|
+
scheduleSettingsPatch: () => scheduleSettingsPatch,
|
|
212
216
|
searchTranscript: () => searchTranscript,
|
|
213
217
|
sendFollowUp: () => sendFollowUp,
|
|
214
218
|
setCaptionLanguage: () => setCaptionLanguage,
|
|
@@ -620,7 +624,8 @@ function parseRoomToken(body, roomName) {
|
|
|
620
624
|
lobby: readBoolean(payload, "lobby", false),
|
|
621
625
|
admissionState: readString(payload, "admission_state") ?? void 0,
|
|
622
626
|
pollSeconds: typeof payload["poll_seconds"] === "number" ? payload["poll_seconds"] : void 0,
|
|
623
|
-
breakoutRoomId: readString(payload, "breakout_room_id") ?? null
|
|
627
|
+
breakoutRoomId: readString(payload, "breakout_room_id") ?? null,
|
|
628
|
+
observersVisibleTo: readString(payload, "observers_visible_to") === "hosts" ? "hosts" : "everyone"
|
|
624
629
|
};
|
|
625
630
|
}
|
|
626
631
|
function createTokenClient(options) {
|
|
@@ -669,6 +674,7 @@ function createTokenClient(options) {
|
|
|
669
674
|
...input.meetingId !== void 0 ? { meeting_id: input.meetingId } : {},
|
|
670
675
|
...input.slug !== void 0 ? { slug: input.slug } : {},
|
|
671
676
|
...input.breakoutRoomId != null ? { breakout_room_id: input.breakoutRoomId } : {},
|
|
677
|
+
...input.observe === true ? { observe: true } : {},
|
|
672
678
|
organization_id: input.identity.organizationId,
|
|
673
679
|
display_name: input.identity.displayName,
|
|
674
680
|
device_id: input.identity.deviceId,
|
|
@@ -740,7 +746,8 @@ function createTokenClient(options) {
|
|
|
740
746
|
return {
|
|
741
747
|
get(input) {
|
|
742
748
|
const entry = cache.get(input.roomName);
|
|
743
|
-
const sameRoom = entry !== void 0 && (entry.token.breakoutRoomId ?? null) === (input.breakoutRoomId ?? null)
|
|
749
|
+
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).
|
|
750
|
+
entry.token.role === "viewer" === (input.observe === true);
|
|
744
751
|
if (entry !== void 0 && sameRoom) {
|
|
745
752
|
if (entry.inFlight !== null) return entry.inFlight;
|
|
746
753
|
if (!expired(entry)) return Promise.resolve(entry.token);
|
|
@@ -1266,6 +1273,9 @@ function isLinkFollower(standing) {
|
|
|
1266
1273
|
function isHostRole(role) {
|
|
1267
1274
|
return role === "host" || role === "cohost";
|
|
1268
1275
|
}
|
|
1276
|
+
function isObserverRole(role) {
|
|
1277
|
+
return role === "viewer";
|
|
1278
|
+
}
|
|
1269
1279
|
var WAITING_ADMISSION_STATES = ["waiting_host", "knocking"];
|
|
1270
1280
|
|
|
1271
1281
|
// src/core/calls.ts
|
|
@@ -1470,388 +1480,49 @@ function createCallCenter(options) {
|
|
|
1470
1480
|
);
|
|
1471
1481
|
return invite;
|
|
1472
1482
|
},
|
|
1473
|
-
async accept(id, mode) {
|
|
1474
|
-
const held = incoming.get(id);
|
|
1475
|
-
if (held !== void 0 && !canTransition(held.state, "connecting")) {
|
|
1476
|
-
throw new MeetError(
|
|
1477
|
-
"conflict",
|
|
1478
|
-
`meet.calls.accept: this call is already ${held.state}`,
|
|
1479
|
-
"A late accept must not resurrect a settled call. Close the ringing UI; the caller has already moved on."
|
|
1480
|
-
);
|
|
1481
|
-
}
|
|
1482
|
-
const settled = await repository.settleCallInvite(id, "connecting", null);
|
|
1483
|
-
settleLocal(settled);
|
|
1484
|
-
channel?.send(MEET_EVENTS.settled, settled);
|
|
1485
|
-
to(settled.callerUserId).send(MEET_EVENTS.settled, { ...settled, mode });
|
|
1486
|
-
return settled;
|
|
1487
|
-
},
|
|
1488
|
-
async decline(id, message) {
|
|
1489
|
-
const settled = await repository.settleCallInvite(id, "declined", message ?? null);
|
|
1490
|
-
settleLocal(settled);
|
|
1491
|
-
channel?.send(MEET_EVENTS.settled, settled);
|
|
1492
|
-
to(settled.callerUserId).send(MEET_EVENTS.settled, settled);
|
|
1493
|
-
return settled;
|
|
1494
|
-
},
|
|
1495
|
-
async cancel(id) {
|
|
1496
|
-
const settled = await repository.settleCallInvite(id, "cancelled", null);
|
|
1497
|
-
clearRing(id);
|
|
1498
|
-
if (outgoing?.id === id) outgoing = settled;
|
|
1499
|
-
for (const callee of settled.calleeUserIds) {
|
|
1500
|
-
to(callee).send(MEET_EVENTS.cancel, settled);
|
|
1501
|
-
}
|
|
1502
|
-
return settled;
|
|
1503
|
-
},
|
|
1504
|
-
incoming: () => [...incoming.values()],
|
|
1505
|
-
outgoing: () => outgoing,
|
|
1506
|
-
ingest,
|
|
1507
|
-
dispose() {
|
|
1508
|
-
for (const id of [...timeouts.keys()]) clearRing(asCallId(id));
|
|
1509
|
-
incoming.clear();
|
|
1510
|
-
for (const handle of outbound.values()) handle.close();
|
|
1511
|
-
outbound.clear();
|
|
1512
|
-
channel?.close();
|
|
1513
|
-
channel = null;
|
|
1514
|
-
}
|
|
1515
|
-
};
|
|
1516
|
-
}
|
|
1517
|
-
|
|
1518
|
-
// src/core/collab.ts
|
|
1519
|
-
var EMPTY_COLLAB = {
|
|
1520
|
-
loaded: false,
|
|
1521
|
-
error: null,
|
|
1522
|
-
settings: null,
|
|
1523
|
-
polls: [],
|
|
1524
|
-
questions: [],
|
|
1525
|
-
strokes: [],
|
|
1526
|
-
breakout: null,
|
|
1527
|
-
broadcast: null,
|
|
1528
|
-
moveRequest: null,
|
|
1529
|
-
panelRequest: null,
|
|
1530
|
-
captionLanguage: null,
|
|
1531
|
-
captionTranslations: {},
|
|
1532
|
-
captionTranslationError: null
|
|
1533
|
-
};
|
|
1534
|
-
function obj(value) {
|
|
1535
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
1536
|
-
}
|
|
1537
|
-
function str(value) {
|
|
1538
|
-
return typeof value === "string" ? value : null;
|
|
1539
|
-
}
|
|
1540
|
-
function num(value) {
|
|
1541
|
-
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
1542
|
-
}
|
|
1543
|
-
function strings(value) {
|
|
1544
|
-
return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
1545
|
-
}
|
|
1546
|
-
function pollFromRow(row) {
|
|
1547
|
-
const id = str(row["id"]);
|
|
1548
|
-
if (id === null) return null;
|
|
1549
|
-
const options = [];
|
|
1550
|
-
for (const raw of Array.isArray(row["options"]) ? row["options"] : []) {
|
|
1551
|
-
const option = obj(raw);
|
|
1552
|
-
const optionId = option === null ? null : str(option["id"]);
|
|
1553
|
-
if (option === null || optionId === null) continue;
|
|
1554
|
-
const votes = num(option["votes"]);
|
|
1555
|
-
options.push({
|
|
1556
|
-
id: optionId,
|
|
1557
|
-
text: str(option["text"]) ?? "",
|
|
1558
|
-
...votes !== null ? { votes } : {},
|
|
1559
|
-
...Array.isArray(option["voters"]) ? { voters: strings(option["voters"]) } : {}
|
|
1560
|
-
});
|
|
1561
|
-
}
|
|
1562
|
-
const state = str(row["state"]);
|
|
1563
|
-
return {
|
|
1564
|
-
id,
|
|
1565
|
-
question: str(row["question"]) ?? "",
|
|
1566
|
-
options,
|
|
1567
|
-
multiple: row["multiple"] === true,
|
|
1568
|
-
anonymous: row["anonymous"] === true,
|
|
1569
|
-
state: state === "live" || state === "closed" ? state : "draft",
|
|
1570
|
-
resultsShared: row["results_shared"] === true,
|
|
1571
|
-
voterCount: num(row["voter_count"]),
|
|
1572
|
-
myVote: strings(row["my_vote"]),
|
|
1573
|
-
createdByName: str(row["created_by_name"]) ?? "",
|
|
1574
|
-
createdAt: str(row["created_at"])
|
|
1575
|
-
};
|
|
1576
|
-
}
|
|
1577
|
-
function questionFromRow(row) {
|
|
1578
|
-
const id = str(row["id"]);
|
|
1579
|
-
if (id === null) return null;
|
|
1580
|
-
const state = str(row["state"]);
|
|
1581
|
-
return {
|
|
1582
|
-
id,
|
|
1583
|
-
text: str(row["text"]) ?? "",
|
|
1584
|
-
askerName: str(row["asker_name"]) ?? "",
|
|
1585
|
-
anonymous: row["anonymous"] === true,
|
|
1586
|
-
state: state === "answered" || state === "dismissed" ? state : "open",
|
|
1587
|
-
answer: str(row["answer"]),
|
|
1588
|
-
answeredByName: str(row["answered_by_name"]),
|
|
1589
|
-
upvotes: num(row["upvotes"]) ?? 0,
|
|
1590
|
-
upvotedByMe: row["upvoted_by_me"] === true,
|
|
1591
|
-
mine: row["mine"] === true,
|
|
1592
|
-
createdAt: str(row["created_at"])
|
|
1593
|
-
};
|
|
1594
|
-
}
|
|
1595
|
-
function strokeFromRow(row) {
|
|
1596
|
-
const id = str(row["id"]);
|
|
1597
|
-
if (id === null || !Array.isArray(row["points"])) return null;
|
|
1598
|
-
const points = [];
|
|
1599
|
-
for (const raw of row["points"]) {
|
|
1600
|
-
if (Array.isArray(raw) && typeof raw[0] === "number" && typeof raw[1] === "number") {
|
|
1601
|
-
points.push([raw[0], raw[1]]);
|
|
1602
|
-
}
|
|
1603
|
-
}
|
|
1604
|
-
return {
|
|
1605
|
-
id,
|
|
1606
|
-
points,
|
|
1607
|
-
color: str(row["color"]) ?? "#111827",
|
|
1608
|
-
width: num(row["width"]) ?? 3,
|
|
1609
|
-
tool: row["tool"] === "highlighter" ? "highlighter" : "pen",
|
|
1610
|
-
by: str(row["by"]) ?? "",
|
|
1611
|
-
byName: str(row["by_name"]) ?? ""
|
|
1612
|
-
};
|
|
1613
|
-
}
|
|
1614
|
-
function broadcastFrom(value) {
|
|
1615
|
-
const row = obj(value);
|
|
1616
|
-
const text3 = row === null ? null : str(row["text"]);
|
|
1617
|
-
if (row === null || text3 === null) return null;
|
|
1618
|
-
return { text: text3, by: str(row["by"]) ?? "", at: str(row["at"]) ?? "" };
|
|
1619
|
-
}
|
|
1620
|
-
function planFromRow(row) {
|
|
1621
|
-
const id = str(row["id"]);
|
|
1622
|
-
if (id === null) return null;
|
|
1623
|
-
const rooms = [];
|
|
1624
|
-
for (const raw of Array.isArray(row["rooms"]) ? row["rooms"] : []) {
|
|
1625
|
-
const room = obj(raw);
|
|
1626
|
-
const roomId = room === null ? null : str(room["id"]);
|
|
1627
|
-
if (room === null || roomId === null) continue;
|
|
1628
|
-
rooms.push({ id: roomId, name: str(room["name"]) ?? roomId, identities: strings(room["identities"]) });
|
|
1629
|
-
}
|
|
1630
|
-
return {
|
|
1631
|
-
id,
|
|
1632
|
-
state: row["state"] === "open" ? "open" : "closed",
|
|
1633
|
-
rooms,
|
|
1634
|
-
allowChoose: row["allow_choose"] === true,
|
|
1635
|
-
minutes: num(row["minutes"]) ?? 0,
|
|
1636
|
-
openedAt: str(row["opened_at"]),
|
|
1637
|
-
endsAt: str(row["ends_at"]),
|
|
1638
|
-
closedAt: str(row["closed_at"]),
|
|
1639
|
-
broadcasts: (Array.isArray(row["broadcasts"]) ? row["broadcasts"] : []).map(broadcastFrom).filter((b) => b !== null)
|
|
1640
|
-
};
|
|
1641
|
-
}
|
|
1642
|
-
function settingsFromRow(row) {
|
|
1643
|
-
if (row === null) return null;
|
|
1644
|
-
return {
|
|
1645
|
-
pollsEnabled: row["polls_enabled"] === true,
|
|
1646
|
-
pollMaxOptions: num(row["poll_max_options"]) ?? 10,
|
|
1647
|
-
qaEnabled: row["qa_enabled"] === true,
|
|
1648
|
-
qaAnonymousAllowed: row["qa_anonymous_allowed"] === true,
|
|
1649
|
-
whiteboardEnabled: row["whiteboard_enabled"] === true,
|
|
1650
|
-
breakoutsEnabled: row["breakouts_enabled"] === true,
|
|
1651
|
-
breakoutMaxRooms: num(row["breakout_max_rooms"]) ?? 20,
|
|
1652
|
-
breakoutDefaultMinutes: num(row["breakout_default_minutes"]) ?? 15,
|
|
1653
|
-
captionTranslationEnabled: row["caption_translation_enabled"] === true,
|
|
1654
|
-
captionTranslationLanguage: str(row["caption_translation_language"]) ?? ""
|
|
1655
|
-
};
|
|
1656
|
-
}
|
|
1657
|
-
function collabFromState(body, previous) {
|
|
1658
|
-
const list = (key, parse) => (Array.isArray(body[key]) ? body[key] : []).map((raw) => {
|
|
1659
|
-
const row = obj(raw);
|
|
1660
|
-
return row === null ? null : parse(row);
|
|
1661
|
-
}).filter((item) => item !== null);
|
|
1662
|
-
const breakoutRow = obj(body["breakout"]);
|
|
1663
|
-
return {
|
|
1664
|
-
...previous,
|
|
1665
|
-
loaded: true,
|
|
1666
|
-
error: null,
|
|
1667
|
-
settings: settingsFromRow(obj(body["settings"])),
|
|
1668
|
-
polls: list("polls", pollFromRow),
|
|
1669
|
-
questions: list("questions", questionFromRow),
|
|
1670
|
-
strokes: list("strokes", strokeFromRow),
|
|
1671
|
-
breakout: breakoutRow === null ? null : planFromRow(breakoutRow)
|
|
1672
|
-
};
|
|
1673
|
-
}
|
|
1674
|
-
function upsert(items, next) {
|
|
1675
|
-
const index = items.findIndex((item) => item.id === next.id);
|
|
1676
|
-
if (index === -1) return [...items, next];
|
|
1677
|
-
const copy = items.slice();
|
|
1678
|
-
copy[index] = next;
|
|
1679
|
-
return copy;
|
|
1680
|
-
}
|
|
1681
|
-
function withItem(collab, row, fromRoom = false) {
|
|
1682
|
-
const kind = str(row["kind"]);
|
|
1683
|
-
if (kind === "poll") {
|
|
1684
|
-
const poll = pollFromRow(row);
|
|
1685
|
-
if (poll === null) return collab;
|
|
1686
|
-
const known = collab.polls.find((p) => p.id === poll.id);
|
|
1687
|
-
let merged = fromRoom && known !== void 0 ? { ...poll, myVote: known.myVote } : poll;
|
|
1688
|
-
if (fromRoom && known !== void 0 && !poll.options.some((o) => o.votes !== void 0)) {
|
|
1689
|
-
const counted = new Map(known.options.map((o) => [o.id, o]));
|
|
1690
|
-
merged = {
|
|
1691
|
-
...merged,
|
|
1692
|
-
voterCount: known.voterCount,
|
|
1693
|
-
options: merged.options.map((o) => {
|
|
1694
|
-
const had = counted.get(o.id);
|
|
1695
|
-
return had === void 0 ? o : { ...o, votes: had.votes, voters: had.voters };
|
|
1696
|
-
})
|
|
1697
|
-
};
|
|
1698
|
-
}
|
|
1699
|
-
return { ...collab, polls: upsert(collab.polls, merged) };
|
|
1700
|
-
}
|
|
1701
|
-
if (kind === "question") {
|
|
1702
|
-
const question = questionFromRow(row);
|
|
1703
|
-
if (question === null) return collab;
|
|
1704
|
-
const known = collab.questions.find((q) => q.id === question.id);
|
|
1705
|
-
const merged = fromRoom && known !== void 0 ? { ...question, mine: known.mine, upvotedByMe: known.upvotedByMe } : question;
|
|
1706
|
-
return { ...collab, questions: upsert(collab.questions, merged) };
|
|
1707
|
-
}
|
|
1708
|
-
if (kind === "stroke") {
|
|
1709
|
-
const stroke = strokeFromRow(row);
|
|
1710
|
-
if (stroke === null) return collab;
|
|
1711
|
-
return { ...collab, strokes: upsert(collab.strokes, stroke) };
|
|
1712
|
-
}
|
|
1713
|
-
if (kind === "breakout") {
|
|
1714
|
-
const plan = planFromRow(row);
|
|
1715
|
-
if (plan === null) return collab;
|
|
1716
|
-
return { ...collab, breakout: plan };
|
|
1717
|
-
}
|
|
1718
|
-
return collab;
|
|
1719
|
-
}
|
|
1720
|
-
function without(collab, ids) {
|
|
1721
|
-
const gone = new Set(ids);
|
|
1722
|
-
return {
|
|
1723
|
-
...collab,
|
|
1724
|
-
polls: collab.polls.filter((p) => !gone.has(p.id)),
|
|
1725
|
-
questions: collab.questions.filter((q) => !gone.has(q.id)),
|
|
1726
|
-
strokes: collab.strokes.filter((s) => !gone.has(s.id))
|
|
1727
|
-
};
|
|
1728
|
-
}
|
|
1729
|
-
function applyCollabPacket(collab, payload, context) {
|
|
1730
|
-
const item = obj(payload["item"]);
|
|
1731
|
-
if (item !== null) {
|
|
1732
|
-
const kind = str(item["kind"]);
|
|
1733
|
-
let next = withItem(collab, item, true);
|
|
1734
|
-
if (kind === "poll" && str(item["state"]) === "live") {
|
|
1735
|
-
const before = collab.polls.find((p) => p.id === str(item["id"]));
|
|
1736
|
-
if (before === void 0 || before.state !== "live") {
|
|
1737
|
-
next = { ...next, panelRequest: { panel: "polls", at: context.now } };
|
|
1738
|
-
}
|
|
1739
|
-
}
|
|
1740
|
-
if (kind === "breakout") {
|
|
1741
|
-
const plan = planFromRow(item);
|
|
1742
|
-
if (plan !== null && plan.state === "closed") {
|
|
1743
|
-
next = { ...next, moveRequest: { roomId: null, at: context.now } };
|
|
1744
|
-
}
|
|
1745
|
-
}
|
|
1746
|
-
const move = obj(payload["move"]);
|
|
1747
|
-
if (move !== null && str(move["identity"]) === context.localIdentity) {
|
|
1748
|
-
next = { ...next, moveRequest: { roomId: str(move["room_id"]), at: context.now } };
|
|
1749
|
-
}
|
|
1750
|
-
return { next };
|
|
1751
|
-
}
|
|
1752
|
-
if (Array.isArray(payload["removed"])) {
|
|
1753
|
-
return { next: without(collab, strings(payload["removed"])) };
|
|
1754
|
-
}
|
|
1755
|
-
if (Array.isArray(payload["hidden"])) {
|
|
1756
|
-
return context.isHost ? { next: null, dropped: "hosts keep dismissed questions" } : { next: without(collab, strings(payload["hidden"])) };
|
|
1757
|
-
}
|
|
1758
|
-
if (payload["cleared"] === "whiteboard") {
|
|
1759
|
-
return { next: { ...collab, strokes: [] } };
|
|
1760
|
-
}
|
|
1761
|
-
const broadcast = broadcastFrom(payload["broadcast"]);
|
|
1762
|
-
if (broadcast !== null) {
|
|
1763
|
-
return { next: { ...collab, broadcast } };
|
|
1764
|
-
}
|
|
1765
|
-
return { next: null, dropped: "a collab packet with nothing this version understands" };
|
|
1766
|
-
}
|
|
1767
|
-
function assignedRoom(plan, identity) {
|
|
1768
|
-
if (plan === null || plan.state !== "open" || identity === null) return null;
|
|
1769
|
-
return plan.rooms.find((room) => room.identities.includes(identity)) ?? null;
|
|
1770
|
-
}
|
|
1771
|
-
function autoAssign(identities, rooms, exclude = []) {
|
|
1772
|
-
const count2 = Math.max(1, Math.floor(rooms));
|
|
1773
|
-
const out = Array.from({ length: count2 }, () => []);
|
|
1774
|
-
const skip = new Set(exclude);
|
|
1775
|
-
let index = 0;
|
|
1776
|
-
for (const identity of identities) {
|
|
1777
|
-
if (skip.has(identity)) continue;
|
|
1778
|
-
out[index % count2].push(identity);
|
|
1779
|
-
index += 1;
|
|
1780
|
-
}
|
|
1781
|
-
return out;
|
|
1782
|
-
}
|
|
1783
|
-
function breakoutRemainingMs(plan, now) {
|
|
1784
|
-
if (plan === null || plan.state !== "open" || plan.endsAt === null) return null;
|
|
1785
|
-
const end = Date.parse(plan.endsAt);
|
|
1786
|
-
return Number.isNaN(end) ? null : Math.max(0, end - now);
|
|
1787
|
-
}
|
|
1788
|
-
function defaultCaptionLanguage(settings, viewerLanguage) {
|
|
1789
|
-
const configured = settings?.captionTranslationLanguage.trim() ?? "";
|
|
1790
|
-
if (configured.length > 0) return configured;
|
|
1791
|
-
const own = (viewerLanguage ?? "").trim();
|
|
1792
|
-
return own.length > 0 ? own : "en";
|
|
1793
|
-
}
|
|
1794
|
-
var CAPTION_LANGUAGES = [
|
|
1795
|
-
{ tag: "en", name: "English" },
|
|
1796
|
-
{ tag: "es", name: "Spanish" },
|
|
1797
|
-
{ tag: "fr", name: "French" },
|
|
1798
|
-
{ tag: "de", name: "German" },
|
|
1799
|
-
{ tag: "it", name: "Italian" },
|
|
1800
|
-
{ tag: "pt", name: "Portuguese" },
|
|
1801
|
-
{ tag: "nl", name: "Dutch" },
|
|
1802
|
-
{ tag: "pl", name: "Polish" },
|
|
1803
|
-
{ tag: "ru", name: "Russian" },
|
|
1804
|
-
{ tag: "uk", name: "Ukrainian" },
|
|
1805
|
-
{ tag: "tr", name: "Turkish" },
|
|
1806
|
-
{ tag: "ar", name: "Arabic" },
|
|
1807
|
-
{ tag: "he", name: "Hebrew" },
|
|
1808
|
-
{ tag: "fa", name: "Persian" },
|
|
1809
|
-
{ tag: "hi", name: "Hindi" },
|
|
1810
|
-
{ tag: "bn", name: "Bengali" },
|
|
1811
|
-
{ tag: "zh", name: "Chinese" },
|
|
1812
|
-
{ tag: "ja", name: "Japanese" },
|
|
1813
|
-
{ tag: "ko", name: "Korean" },
|
|
1814
|
-
{ tag: "vi", name: "Vietnamese" },
|
|
1815
|
-
{ tag: "th", name: "Thai" },
|
|
1816
|
-
{ tag: "id", name: "Indonesian" },
|
|
1817
|
-
{ tag: "sv", name: "Swedish" }
|
|
1818
|
-
];
|
|
1819
|
-
async function loadMeetingActivities(api, meetingId, meetingPass = null) {
|
|
1820
|
-
let response;
|
|
1821
|
-
try {
|
|
1822
|
-
response = await api.request({
|
|
1823
|
-
path: `${MEET_ROUTES.collab}?meeting_id=${encodeURIComponent(meetingId)}`,
|
|
1824
|
-
method: "GET",
|
|
1825
|
-
operation: "meet.loadMeetingActivities",
|
|
1826
|
-
requireAuth: meetingPass === null,
|
|
1827
|
-
...meetingPass !== null ? { headers: { [MEETING_PASS_HEADER]: meetingPass } } : {}
|
|
1828
|
-
});
|
|
1829
|
-
} catch (error) {
|
|
1830
|
-
return {
|
|
1831
|
-
collab: null,
|
|
1832
|
-
refusal: {
|
|
1833
|
-
message: `Polls, questions and the whiteboard could not be read (${error.message}).`,
|
|
1834
|
-
remedy: error.remedy ?? "Reload the page."
|
|
1483
|
+
async accept(id, mode) {
|
|
1484
|
+
const held = incoming.get(id);
|
|
1485
|
+
if (held !== void 0 && !canTransition(held.state, "connecting")) {
|
|
1486
|
+
throw new MeetError(
|
|
1487
|
+
"conflict",
|
|
1488
|
+
`meet.calls.accept: this call is already ${held.state}`,
|
|
1489
|
+
"A late accept must not resurrect a settled call. Close the ringing UI; the caller has already moved on."
|
|
1490
|
+
);
|
|
1835
1491
|
}
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1492
|
+
const settled = await repository.settleCallInvite(id, "connecting", null);
|
|
1493
|
+
settleLocal(settled);
|
|
1494
|
+
channel?.send(MEET_EVENTS.settled, settled);
|
|
1495
|
+
to(settled.callerUserId).send(MEET_EVENTS.settled, { ...settled, mode });
|
|
1496
|
+
return settled;
|
|
1497
|
+
},
|
|
1498
|
+
async decline(id, message) {
|
|
1499
|
+
const settled = await repository.settleCallInvite(id, "declined", message ?? null);
|
|
1500
|
+
settleLocal(settled);
|
|
1501
|
+
channel?.send(MEET_EVENTS.settled, settled);
|
|
1502
|
+
to(settled.callerUserId).send(MEET_EVENTS.settled, settled);
|
|
1503
|
+
return settled;
|
|
1504
|
+
},
|
|
1505
|
+
async cancel(id) {
|
|
1506
|
+
const settled = await repository.settleCallInvite(id, "cancelled", null);
|
|
1507
|
+
clearRing(id);
|
|
1508
|
+
if (outgoing?.id === id) outgoing = settled;
|
|
1509
|
+
for (const callee of settled.calleeUserIds) {
|
|
1510
|
+
to(callee).send(MEET_EVENTS.cancel, settled);
|
|
1851
1511
|
}
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1512
|
+
return settled;
|
|
1513
|
+
},
|
|
1514
|
+
incoming: () => [...incoming.values()],
|
|
1515
|
+
outgoing: () => outgoing,
|
|
1516
|
+
ingest,
|
|
1517
|
+
dispose() {
|
|
1518
|
+
for (const id of [...timeouts.keys()]) clearRing(asCallId(id));
|
|
1519
|
+
incoming.clear();
|
|
1520
|
+
for (const handle of outbound.values()) handle.close();
|
|
1521
|
+
outbound.clear();
|
|
1522
|
+
channel?.close();
|
|
1523
|
+
channel = null;
|
|
1524
|
+
}
|
|
1525
|
+
};
|
|
1855
1526
|
}
|
|
1856
1527
|
|
|
1857
1528
|
// src/core/repository.ts
|
|
@@ -2046,7 +1717,7 @@ var OCCURRENCE_STATES = ["scheduled", "moved", "cancelled"];
|
|
|
2046
1717
|
function rsvpState(value) {
|
|
2047
1718
|
return RSVP_STATES.includes(value) ? value : "needs_action";
|
|
2048
1719
|
}
|
|
2049
|
-
function
|
|
1720
|
+
function num(row, key) {
|
|
2050
1721
|
const value = row[key];
|
|
2051
1722
|
return typeof value === "number" ? value : null;
|
|
2052
1723
|
}
|
|
@@ -2068,7 +1739,7 @@ function projectInvitee(row) {
|
|
|
2068
1739
|
rsvpState: rsvpState(text(row, "rsvp_state")),
|
|
2069
1740
|
respondedAt: when(row, "responded_at"),
|
|
2070
1741
|
rsvpNote: text(row, "rsvp_note"),
|
|
2071
|
-
lastSentSequence:
|
|
1742
|
+
lastSentSequence: num(row, "last_sent_sequence"),
|
|
2072
1743
|
lastSentAt: when(row, "last_sent_at")
|
|
2073
1744
|
};
|
|
2074
1745
|
}
|
|
@@ -2079,10 +1750,10 @@ function projectOccurrence(row) {
|
|
|
2079
1750
|
meetingId: asMeetingId(requireText(row, "meeting_id", operation)),
|
|
2080
1751
|
originalStart: when(row, "original_start") ?? requireText(row, "original_start", operation),
|
|
2081
1752
|
occurrenceStart: when(row, "occurrence_start") ?? requireText(row, "occurrence_start", operation),
|
|
2082
|
-
durationMinutes:
|
|
1753
|
+
durationMinutes: num(row, "duration_minutes"),
|
|
2083
1754
|
// An unknown state is shown as scheduled, never dropped: the row is real.
|
|
2084
1755
|
state: OCCURRENCE_STATES.includes(state) ? state : "scheduled",
|
|
2085
|
-
sequence:
|
|
1756
|
+
sequence: num(row, "sequence") ?? 0
|
|
2086
1757
|
};
|
|
2087
1758
|
}
|
|
2088
1759
|
function projectUpcoming(row) {
|
|
@@ -2111,9 +1782,9 @@ function projectOverride(row) {
|
|
|
2111
1782
|
originalStart: when(row, "original_start") ?? requireText(row, "original_start", operation),
|
|
2112
1783
|
state: text(row, "state") === "moved" ? "moved" : "cancelled",
|
|
2113
1784
|
newStart: when(row, "new_start"),
|
|
2114
|
-
newDurationMinutes:
|
|
1785
|
+
newDurationMinutes: num(row, "new_duration_minutes"),
|
|
2115
1786
|
reason: text(row, "reason"),
|
|
2116
|
-
calendarSequence:
|
|
1787
|
+
calendarSequence: num(row, "calendar_sequence") ?? 0,
|
|
2117
1788
|
deletedAt: when(row, "deleted_at")
|
|
2118
1789
|
};
|
|
2119
1790
|
}
|
|
@@ -2137,7 +1808,7 @@ function projectRsvpInvitation(body) {
|
|
|
2137
1808
|
title: text(meeting, "title") ?? "Meeting",
|
|
2138
1809
|
slug: requireText(meeting, "slug", operation),
|
|
2139
1810
|
scheduledFor: when(meeting, "scheduled_for"),
|
|
2140
|
-
durationMinutes:
|
|
1811
|
+
durationMinutes: num(meeting, "duration_minutes"),
|
|
2141
1812
|
timeZone: text(meeting, "time_zone") ?? "UTC",
|
|
2142
1813
|
agenda: text(meeting, "agenda"),
|
|
2143
1814
|
recurrenceRule: text(meeting, "recurrence_rule"),
|
|
@@ -2365,7 +2036,7 @@ function createMeetRepository(options) {
|
|
|
2365
2036
|
p_duration_minutes: input.durationMinutes ?? null,
|
|
2366
2037
|
p_agenda: input.agenda ?? null,
|
|
2367
2038
|
p_recurrence_rule: input.recurrenceRule ?? null,
|
|
2368
|
-
p_settings:
|
|
2039
|
+
p_settings: scheduleSettingsPatch(input.settings ?? {}, input.appPanel, input.observers)
|
|
2369
2040
|
})
|
|
2370
2041
|
);
|
|
2371
2042
|
return projectMeeting(row);
|
|
@@ -2700,74 +2371,447 @@ function createMeetRepository(options) {
|
|
|
2700
2371
|
}
|
|
2701
2372
|
};
|
|
2702
2373
|
}
|
|
2703
|
-
var LIBRARY_STATES = [
|
|
2704
|
-
"idle",
|
|
2705
|
-
"starting",
|
|
2706
|
-
"recording",
|
|
2707
|
-
"stopping",
|
|
2708
|
-
"processing",
|
|
2709
|
-
"available",
|
|
2710
|
-
"expired",
|
|
2711
|
-
"failed"
|
|
2712
|
-
];
|
|
2713
|
-
function projectLibraryRecording(row) {
|
|
2714
|
-
const operation = "meet.projectLibraryRecording";
|
|
2715
|
-
const state = text(row, "state");
|
|
2716
|
-
const role = text(row, "my_role");
|
|
2374
|
+
var LIBRARY_STATES = [
|
|
2375
|
+
"idle",
|
|
2376
|
+
"starting",
|
|
2377
|
+
"recording",
|
|
2378
|
+
"stopping",
|
|
2379
|
+
"processing",
|
|
2380
|
+
"available",
|
|
2381
|
+
"expired",
|
|
2382
|
+
"failed"
|
|
2383
|
+
];
|
|
2384
|
+
function projectLibraryRecording(row) {
|
|
2385
|
+
const operation = "meet.projectLibraryRecording";
|
|
2386
|
+
const state = text(row, "state");
|
|
2387
|
+
const role = text(row, "my_role");
|
|
2388
|
+
return {
|
|
2389
|
+
id: requireText(row, "recording_id", operation),
|
|
2390
|
+
meetingId: asMeetingId(requireText(row, "meeting_id", operation)),
|
|
2391
|
+
meetingTitle: text(row, "meeting_title") ?? "Meeting",
|
|
2392
|
+
meetingSlug: requireText(row, "meeting_slug", operation),
|
|
2393
|
+
role: role === "host" || role === "cohost" || role === "invitee" ? role : "attendee",
|
|
2394
|
+
state: LIBRARY_STATES.includes(state) ? state : "failed",
|
|
2395
|
+
title: text(row, "recording_title"),
|
|
2396
|
+
fileId: text(row, "file_id"),
|
|
2397
|
+
startedAt: text(row, "started_at"),
|
|
2398
|
+
endedAt: text(row, "ended_at"),
|
|
2399
|
+
durationMs: num(row, "duration_ms"),
|
|
2400
|
+
sizeBytes: num(row, "size_bytes"),
|
|
2401
|
+
failureReason: text(row, "failure_reason"),
|
|
2402
|
+
archivedAt: text(row, "deleted_at"),
|
|
2403
|
+
organizationId: asOrganizationId(requireText(row, "organization_id", operation))
|
|
2404
|
+
};
|
|
2405
|
+
}
|
|
2406
|
+
var SEARCH_SOURCES = [
|
|
2407
|
+
"title",
|
|
2408
|
+
"summary",
|
|
2409
|
+
"decision",
|
|
2410
|
+
"action_item",
|
|
2411
|
+
"note",
|
|
2412
|
+
"transcript"
|
|
2413
|
+
];
|
|
2414
|
+
function projectSearchHit(row) {
|
|
2415
|
+
const operation = "meet.projectSearchHit";
|
|
2416
|
+
const source = text(row, "source");
|
|
2417
|
+
return {
|
|
2418
|
+
meetingId: asMeetingId(requireText(row, "meeting_id", operation)),
|
|
2419
|
+
meetingTitle: text(row, "meeting_title") ?? "Meeting",
|
|
2420
|
+
meetingSlug: requireText(row, "meeting_slug", operation),
|
|
2421
|
+
meetingAt: text(row, "meeting_at"),
|
|
2422
|
+
source: SEARCH_SOURCES.includes(source) ? source : "note",
|
|
2423
|
+
refId: requireText(row, "ref_id", operation),
|
|
2424
|
+
speaker: text(row, "speaker"),
|
|
2425
|
+
snippet: text(row, "snippet") ?? "",
|
|
2426
|
+
at: text(row, "said_at"),
|
|
2427
|
+
rank: num(row, "rank") ?? 0
|
|
2428
|
+
};
|
|
2429
|
+
}
|
|
2430
|
+
function snippetRuns(snippet) {
|
|
2431
|
+
const runs = [];
|
|
2432
|
+
const pattern = /⟦([^⟧]*)⟧/g;
|
|
2433
|
+
let last = 0;
|
|
2434
|
+
for (const match of snippet.matchAll(pattern)) {
|
|
2435
|
+
const start = match.index ?? 0;
|
|
2436
|
+
if (start > last) runs.push({ text: snippet.slice(last, start), hit: false });
|
|
2437
|
+
runs.push({ text: match[1] ?? "", hit: true });
|
|
2438
|
+
last = start + match[0].length;
|
|
2439
|
+
}
|
|
2440
|
+
if (last < snippet.length) runs.push({ text: snippet.slice(last), hit: false });
|
|
2441
|
+
return runs;
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
// src/core/app-panel.ts
|
|
2445
|
+
function appPanelOf(meeting) {
|
|
2446
|
+
const raw = meeting?.metadata?.["app_panel"];
|
|
2447
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null;
|
|
2448
|
+
const key = raw["key"];
|
|
2449
|
+
const recordId = raw["record_id"];
|
|
2450
|
+
if (typeof key !== "string" || key.length === 0) return null;
|
|
2451
|
+
if (typeof recordId !== "string" || recordId.length === 0) return null;
|
|
2452
|
+
return { key, recordId };
|
|
2453
|
+
}
|
|
2454
|
+
function scheduleSettingsPatch(settings, appPanel, observers) {
|
|
2455
|
+
const patch = settingsPatch(settings);
|
|
2456
|
+
if (appPanel !== void 0) patch["app_panel"] = { key: appPanel.key, record_id: appPanel.recordId };
|
|
2457
|
+
if (observers !== void 0 && observers.length > 0) patch["observers"] = [...observers];
|
|
2458
|
+
return patch;
|
|
2459
|
+
}
|
|
2460
|
+
function focusFromRow(value) {
|
|
2461
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
2462
|
+
const row = value;
|
|
2463
|
+
if (typeof row["panel"] !== "string") return null;
|
|
2464
|
+
return {
|
|
2465
|
+
panel: row["panel"],
|
|
2466
|
+
section: typeof row["section"] === "string" ? row["section"] : "",
|
|
2467
|
+
byName: typeof row["by_name"] === "string" ? row["by_name"] : "",
|
|
2468
|
+
at: typeof row["at"] === "string" ? row["at"] : ""
|
|
2469
|
+
};
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
// src/core/collab.ts
|
|
2473
|
+
var EMPTY_COLLAB = {
|
|
2474
|
+
loaded: false,
|
|
2475
|
+
error: null,
|
|
2476
|
+
settings: null,
|
|
2477
|
+
polls: [],
|
|
2478
|
+
questions: [],
|
|
2479
|
+
strokes: [],
|
|
2480
|
+
breakout: null,
|
|
2481
|
+
broadcast: null,
|
|
2482
|
+
moveRequest: null,
|
|
2483
|
+
panelRequest: null,
|
|
2484
|
+
captionLanguage: null,
|
|
2485
|
+
captionTranslations: {},
|
|
2486
|
+
captionTranslationError: null,
|
|
2487
|
+
focus: null
|
|
2488
|
+
};
|
|
2489
|
+
function obj(value) {
|
|
2490
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
2491
|
+
}
|
|
2492
|
+
function str(value) {
|
|
2493
|
+
return typeof value === "string" ? value : null;
|
|
2494
|
+
}
|
|
2495
|
+
function num2(value) {
|
|
2496
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
2497
|
+
}
|
|
2498
|
+
function strings(value) {
|
|
2499
|
+
return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
2500
|
+
}
|
|
2501
|
+
function pollFromRow(row) {
|
|
2502
|
+
const id = str(row["id"]);
|
|
2503
|
+
if (id === null) return null;
|
|
2504
|
+
const options = [];
|
|
2505
|
+
for (const raw of Array.isArray(row["options"]) ? row["options"] : []) {
|
|
2506
|
+
const option = obj(raw);
|
|
2507
|
+
const optionId = option === null ? null : str(option["id"]);
|
|
2508
|
+
if (option === null || optionId === null) continue;
|
|
2509
|
+
const votes = num2(option["votes"]);
|
|
2510
|
+
options.push({
|
|
2511
|
+
id: optionId,
|
|
2512
|
+
text: str(option["text"]) ?? "",
|
|
2513
|
+
...votes !== null ? { votes } : {},
|
|
2514
|
+
...Array.isArray(option["voters"]) ? { voters: strings(option["voters"]) } : {}
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
const state = str(row["state"]);
|
|
2518
|
+
return {
|
|
2519
|
+
id,
|
|
2520
|
+
question: str(row["question"]) ?? "",
|
|
2521
|
+
options,
|
|
2522
|
+
multiple: row["multiple"] === true,
|
|
2523
|
+
anonymous: row["anonymous"] === true,
|
|
2524
|
+
state: state === "live" || state === "closed" ? state : "draft",
|
|
2525
|
+
resultsShared: row["results_shared"] === true,
|
|
2526
|
+
voterCount: num2(row["voter_count"]),
|
|
2527
|
+
myVote: strings(row["my_vote"]),
|
|
2528
|
+
createdByName: str(row["created_by_name"]) ?? "",
|
|
2529
|
+
createdAt: str(row["created_at"])
|
|
2530
|
+
};
|
|
2531
|
+
}
|
|
2532
|
+
function questionFromRow(row) {
|
|
2533
|
+
const id = str(row["id"]);
|
|
2534
|
+
if (id === null) return null;
|
|
2535
|
+
const state = str(row["state"]);
|
|
2536
|
+
return {
|
|
2537
|
+
id,
|
|
2538
|
+
text: str(row["text"]) ?? "",
|
|
2539
|
+
askerName: str(row["asker_name"]) ?? "",
|
|
2540
|
+
anonymous: row["anonymous"] === true,
|
|
2541
|
+
state: state === "answered" || state === "dismissed" ? state : "open",
|
|
2542
|
+
answer: str(row["answer"]),
|
|
2543
|
+
answeredByName: str(row["answered_by_name"]),
|
|
2544
|
+
upvotes: num2(row["upvotes"]) ?? 0,
|
|
2545
|
+
upvotedByMe: row["upvoted_by_me"] === true,
|
|
2546
|
+
mine: row["mine"] === true,
|
|
2547
|
+
createdAt: str(row["created_at"])
|
|
2548
|
+
};
|
|
2549
|
+
}
|
|
2550
|
+
function strokeFromRow(row) {
|
|
2551
|
+
const id = str(row["id"]);
|
|
2552
|
+
if (id === null || !Array.isArray(row["points"])) return null;
|
|
2553
|
+
const points = [];
|
|
2554
|
+
for (const raw of row["points"]) {
|
|
2555
|
+
if (Array.isArray(raw) && typeof raw[0] === "number" && typeof raw[1] === "number") {
|
|
2556
|
+
points.push([raw[0], raw[1]]);
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
return {
|
|
2560
|
+
id,
|
|
2561
|
+
points,
|
|
2562
|
+
color: str(row["color"]) ?? "#111827",
|
|
2563
|
+
width: num2(row["width"]) ?? 3,
|
|
2564
|
+
tool: row["tool"] === "highlighter" ? "highlighter" : "pen",
|
|
2565
|
+
by: str(row["by"]) ?? "",
|
|
2566
|
+
byName: str(row["by_name"]) ?? ""
|
|
2567
|
+
};
|
|
2568
|
+
}
|
|
2569
|
+
function broadcastFrom(value) {
|
|
2570
|
+
const row = obj(value);
|
|
2571
|
+
const text3 = row === null ? null : str(row["text"]);
|
|
2572
|
+
if (row === null || text3 === null) return null;
|
|
2573
|
+
return { text: text3, by: str(row["by"]) ?? "", at: str(row["at"]) ?? "" };
|
|
2574
|
+
}
|
|
2575
|
+
function planFromRow(row) {
|
|
2576
|
+
const id = str(row["id"]);
|
|
2577
|
+
if (id === null) return null;
|
|
2578
|
+
const rooms = [];
|
|
2579
|
+
for (const raw of Array.isArray(row["rooms"]) ? row["rooms"] : []) {
|
|
2580
|
+
const room = obj(raw);
|
|
2581
|
+
const roomId = room === null ? null : str(room["id"]);
|
|
2582
|
+
if (room === null || roomId === null) continue;
|
|
2583
|
+
rooms.push({ id: roomId, name: str(room["name"]) ?? roomId, identities: strings(room["identities"]) });
|
|
2584
|
+
}
|
|
2585
|
+
return {
|
|
2586
|
+
id,
|
|
2587
|
+
state: row["state"] === "open" ? "open" : "closed",
|
|
2588
|
+
rooms,
|
|
2589
|
+
allowChoose: row["allow_choose"] === true,
|
|
2590
|
+
minutes: num2(row["minutes"]) ?? 0,
|
|
2591
|
+
openedAt: str(row["opened_at"]),
|
|
2592
|
+
endsAt: str(row["ends_at"]),
|
|
2593
|
+
closedAt: str(row["closed_at"]),
|
|
2594
|
+
broadcasts: (Array.isArray(row["broadcasts"]) ? row["broadcasts"] : []).map(broadcastFrom).filter((b) => b !== null)
|
|
2595
|
+
};
|
|
2596
|
+
}
|
|
2597
|
+
function settingsFromRow(row) {
|
|
2598
|
+
if (row === null) return null;
|
|
2599
|
+
return {
|
|
2600
|
+
pollsEnabled: row["polls_enabled"] === true,
|
|
2601
|
+
pollMaxOptions: num2(row["poll_max_options"]) ?? 10,
|
|
2602
|
+
qaEnabled: row["qa_enabled"] === true,
|
|
2603
|
+
qaAnonymousAllowed: row["qa_anonymous_allowed"] === true,
|
|
2604
|
+
whiteboardEnabled: row["whiteboard_enabled"] === true,
|
|
2605
|
+
breakoutsEnabled: row["breakouts_enabled"] === true,
|
|
2606
|
+
breakoutMaxRooms: num2(row["breakout_max_rooms"]) ?? 20,
|
|
2607
|
+
breakoutDefaultMinutes: num2(row["breakout_default_minutes"]) ?? 15,
|
|
2608
|
+
captionTranslationEnabled: row["caption_translation_enabled"] === true,
|
|
2609
|
+
captionTranslationLanguage: str(row["caption_translation_language"]) ?? ""
|
|
2610
|
+
};
|
|
2611
|
+
}
|
|
2612
|
+
function collabFromState(body, previous) {
|
|
2613
|
+
const list = (key, parse) => (Array.isArray(body[key]) ? body[key] : []).map((raw) => {
|
|
2614
|
+
const row = obj(raw);
|
|
2615
|
+
return row === null ? null : parse(row);
|
|
2616
|
+
}).filter((item) => item !== null);
|
|
2617
|
+
const breakoutRow = obj(body["breakout"]);
|
|
2717
2618
|
return {
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
endedAt: text(row, "ended_at"),
|
|
2728
|
-
durationMs: num2(row, "duration_ms"),
|
|
2729
|
-
sizeBytes: num2(row, "size_bytes"),
|
|
2730
|
-
failureReason: text(row, "failure_reason"),
|
|
2731
|
-
archivedAt: text(row, "deleted_at"),
|
|
2732
|
-
organizationId: asOrganizationId(requireText(row, "organization_id", operation))
|
|
2619
|
+
...previous,
|
|
2620
|
+
loaded: true,
|
|
2621
|
+
error: null,
|
|
2622
|
+
settings: settingsFromRow(obj(body["settings"])),
|
|
2623
|
+
polls: list("polls", pollFromRow),
|
|
2624
|
+
questions: list("questions", questionFromRow),
|
|
2625
|
+
strokes: list("strokes", strokeFromRow),
|
|
2626
|
+
breakout: breakoutRow === null ? null : planFromRow(breakoutRow),
|
|
2627
|
+
focus: focusFromRow(body["focus"])
|
|
2733
2628
|
};
|
|
2734
2629
|
}
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2630
|
+
function upsert(items, next) {
|
|
2631
|
+
const index = items.findIndex((item) => item.id === next.id);
|
|
2632
|
+
if (index === -1) return [...items, next];
|
|
2633
|
+
const copy = items.slice();
|
|
2634
|
+
copy[index] = next;
|
|
2635
|
+
return copy;
|
|
2636
|
+
}
|
|
2637
|
+
function withItem(collab, row, fromRoom = false) {
|
|
2638
|
+
const kind = str(row["kind"]);
|
|
2639
|
+
if (kind === "poll") {
|
|
2640
|
+
const poll = pollFromRow(row);
|
|
2641
|
+
if (poll === null) return collab;
|
|
2642
|
+
const known = collab.polls.find((p) => p.id === poll.id);
|
|
2643
|
+
let merged = fromRoom && known !== void 0 ? { ...poll, myVote: known.myVote } : poll;
|
|
2644
|
+
if (fromRoom && known !== void 0 && !poll.options.some((o) => o.votes !== void 0)) {
|
|
2645
|
+
const counted = new Map(known.options.map((o) => [o.id, o]));
|
|
2646
|
+
merged = {
|
|
2647
|
+
...merged,
|
|
2648
|
+
voterCount: known.voterCount,
|
|
2649
|
+
options: merged.options.map((o) => {
|
|
2650
|
+
const had = counted.get(o.id);
|
|
2651
|
+
return had === void 0 ? o : { ...o, votes: had.votes, voters: had.voters };
|
|
2652
|
+
})
|
|
2653
|
+
};
|
|
2654
|
+
}
|
|
2655
|
+
return { ...collab, polls: upsert(collab.polls, merged) };
|
|
2656
|
+
}
|
|
2657
|
+
if (kind === "question") {
|
|
2658
|
+
const question = questionFromRow(row);
|
|
2659
|
+
if (question === null) return collab;
|
|
2660
|
+
const known = collab.questions.find((q) => q.id === question.id);
|
|
2661
|
+
const merged = fromRoom && known !== void 0 ? { ...question, mine: known.mine, upvotedByMe: known.upvotedByMe } : question;
|
|
2662
|
+
return { ...collab, questions: upsert(collab.questions, merged) };
|
|
2663
|
+
}
|
|
2664
|
+
if (kind === "stroke") {
|
|
2665
|
+
const stroke = strokeFromRow(row);
|
|
2666
|
+
if (stroke === null) return collab;
|
|
2667
|
+
return { ...collab, strokes: upsert(collab.strokes, stroke) };
|
|
2668
|
+
}
|
|
2669
|
+
if (kind === "breakout") {
|
|
2670
|
+
const plan = planFromRow(row);
|
|
2671
|
+
if (plan === null) return collab;
|
|
2672
|
+
return { ...collab, breakout: plan };
|
|
2673
|
+
}
|
|
2674
|
+
return collab;
|
|
2675
|
+
}
|
|
2676
|
+
function without(collab, ids) {
|
|
2677
|
+
const gone = new Set(ids);
|
|
2746
2678
|
return {
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
source: SEARCH_SOURCES.includes(source) ? source : "note",
|
|
2752
|
-
refId: requireText(row, "ref_id", operation),
|
|
2753
|
-
speaker: text(row, "speaker"),
|
|
2754
|
-
snippet: text(row, "snippet") ?? "",
|
|
2755
|
-
at: text(row, "said_at"),
|
|
2756
|
-
rank: num2(row, "rank") ?? 0
|
|
2679
|
+
...collab,
|
|
2680
|
+
polls: collab.polls.filter((p) => !gone.has(p.id)),
|
|
2681
|
+
questions: collab.questions.filter((q) => !gone.has(q.id)),
|
|
2682
|
+
strokes: collab.strokes.filter((s) => !gone.has(s.id))
|
|
2757
2683
|
};
|
|
2758
2684
|
}
|
|
2759
|
-
function
|
|
2760
|
-
const
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2685
|
+
function applyCollabPacket(collab, payload, context) {
|
|
2686
|
+
const item = obj(payload["item"]);
|
|
2687
|
+
if (item !== null) {
|
|
2688
|
+
const kind = str(item["kind"]);
|
|
2689
|
+
let next = withItem(collab, item, true);
|
|
2690
|
+
if (kind === "poll" && str(item["state"]) === "live") {
|
|
2691
|
+
const before = collab.polls.find((p) => p.id === str(item["id"]));
|
|
2692
|
+
if (before === void 0 || before.state !== "live") {
|
|
2693
|
+
next = { ...next, panelRequest: { panel: "polls", at: context.now } };
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
if (kind === "breakout") {
|
|
2697
|
+
const plan = planFromRow(item);
|
|
2698
|
+
if (plan !== null && plan.state === "closed") {
|
|
2699
|
+
next = { ...next, moveRequest: { roomId: null, at: context.now } };
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
const move = obj(payload["move"]);
|
|
2703
|
+
if (move !== null && str(move["identity"]) === context.localIdentity) {
|
|
2704
|
+
next = { ...next, moveRequest: { roomId: str(move["room_id"]), at: context.now } };
|
|
2705
|
+
}
|
|
2706
|
+
return { next };
|
|
2768
2707
|
}
|
|
2769
|
-
if (
|
|
2770
|
-
|
|
2708
|
+
if (payload["focus"] !== void 0) {
|
|
2709
|
+
const focus = focusFromRow(payload["focus"]);
|
|
2710
|
+
return focus === null ? { next: null, dropped: "a focus packet without a panel" } : { next: { ...collab, focus } };
|
|
2711
|
+
}
|
|
2712
|
+
if (Array.isArray(payload["removed"])) {
|
|
2713
|
+
return { next: without(collab, strings(payload["removed"])) };
|
|
2714
|
+
}
|
|
2715
|
+
if (Array.isArray(payload["hidden"])) {
|
|
2716
|
+
return context.isHost ? { next: null, dropped: "hosts keep dismissed questions" } : { next: without(collab, strings(payload["hidden"])) };
|
|
2717
|
+
}
|
|
2718
|
+
if (payload["cleared"] === "whiteboard") {
|
|
2719
|
+
return { next: { ...collab, strokes: [] } };
|
|
2720
|
+
}
|
|
2721
|
+
const broadcast = broadcastFrom(payload["broadcast"]);
|
|
2722
|
+
if (broadcast !== null) {
|
|
2723
|
+
return { next: { ...collab, broadcast } };
|
|
2724
|
+
}
|
|
2725
|
+
return { next: null, dropped: "a collab packet with nothing this version understands" };
|
|
2726
|
+
}
|
|
2727
|
+
function assignedRoom(plan, identity) {
|
|
2728
|
+
if (plan === null || plan.state !== "open" || identity === null) return null;
|
|
2729
|
+
return plan.rooms.find((room) => room.identities.includes(identity)) ?? null;
|
|
2730
|
+
}
|
|
2731
|
+
function autoAssign(identities, rooms, exclude = []) {
|
|
2732
|
+
const count2 = Math.max(1, Math.floor(rooms));
|
|
2733
|
+
const out = Array.from({ length: count2 }, () => []);
|
|
2734
|
+
const skip = new Set(exclude);
|
|
2735
|
+
let index = 0;
|
|
2736
|
+
for (const identity of identities) {
|
|
2737
|
+
if (skip.has(identity)) continue;
|
|
2738
|
+
out[index % count2].push(identity);
|
|
2739
|
+
index += 1;
|
|
2740
|
+
}
|
|
2741
|
+
return out;
|
|
2742
|
+
}
|
|
2743
|
+
function breakoutRemainingMs(plan, now) {
|
|
2744
|
+
if (plan === null || plan.state !== "open" || plan.endsAt === null) return null;
|
|
2745
|
+
const end = Date.parse(plan.endsAt);
|
|
2746
|
+
return Number.isNaN(end) ? null : Math.max(0, end - now);
|
|
2747
|
+
}
|
|
2748
|
+
function defaultCaptionLanguage(settings, viewerLanguage) {
|
|
2749
|
+
const configured = settings?.captionTranslationLanguage.trim() ?? "";
|
|
2750
|
+
if (configured.length > 0) return configured;
|
|
2751
|
+
const own = (viewerLanguage ?? "").trim();
|
|
2752
|
+
return own.length > 0 ? own : "en";
|
|
2753
|
+
}
|
|
2754
|
+
var CAPTION_LANGUAGES = [
|
|
2755
|
+
{ tag: "en", name: "English" },
|
|
2756
|
+
{ tag: "es", name: "Spanish" },
|
|
2757
|
+
{ tag: "fr", name: "French" },
|
|
2758
|
+
{ tag: "de", name: "German" },
|
|
2759
|
+
{ tag: "it", name: "Italian" },
|
|
2760
|
+
{ tag: "pt", name: "Portuguese" },
|
|
2761
|
+
{ tag: "nl", name: "Dutch" },
|
|
2762
|
+
{ tag: "pl", name: "Polish" },
|
|
2763
|
+
{ tag: "ru", name: "Russian" },
|
|
2764
|
+
{ tag: "uk", name: "Ukrainian" },
|
|
2765
|
+
{ tag: "tr", name: "Turkish" },
|
|
2766
|
+
{ tag: "ar", name: "Arabic" },
|
|
2767
|
+
{ tag: "he", name: "Hebrew" },
|
|
2768
|
+
{ tag: "fa", name: "Persian" },
|
|
2769
|
+
{ tag: "hi", name: "Hindi" },
|
|
2770
|
+
{ tag: "bn", name: "Bengali" },
|
|
2771
|
+
{ tag: "zh", name: "Chinese" },
|
|
2772
|
+
{ tag: "ja", name: "Japanese" },
|
|
2773
|
+
{ tag: "ko", name: "Korean" },
|
|
2774
|
+
{ tag: "vi", name: "Vietnamese" },
|
|
2775
|
+
{ tag: "th", name: "Thai" },
|
|
2776
|
+
{ tag: "id", name: "Indonesian" },
|
|
2777
|
+
{ tag: "sv", name: "Swedish" }
|
|
2778
|
+
];
|
|
2779
|
+
async function loadMeetingActivities(api, meetingId, meetingPass = null) {
|
|
2780
|
+
let response;
|
|
2781
|
+
try {
|
|
2782
|
+
response = await api.request({
|
|
2783
|
+
path: `${MEET_ROUTES.collab}?meeting_id=${encodeURIComponent(meetingId)}`,
|
|
2784
|
+
method: "GET",
|
|
2785
|
+
operation: "meet.loadMeetingActivities",
|
|
2786
|
+
requireAuth: meetingPass === null,
|
|
2787
|
+
...meetingPass !== null ? { headers: { [MEETING_PASS_HEADER]: meetingPass } } : {}
|
|
2788
|
+
});
|
|
2789
|
+
} catch (error) {
|
|
2790
|
+
return {
|
|
2791
|
+
collab: null,
|
|
2792
|
+
refusal: {
|
|
2793
|
+
message: `Polls, questions and the whiteboard could not be read (${error.message}).`,
|
|
2794
|
+
remedy: error.remedy ?? "Reload the page."
|
|
2795
|
+
}
|
|
2796
|
+
};
|
|
2797
|
+
}
|
|
2798
|
+
if (!response.ok) {
|
|
2799
|
+
let body = null;
|
|
2800
|
+
try {
|
|
2801
|
+
body = await response.json();
|
|
2802
|
+
} catch {
|
|
2803
|
+
body = null;
|
|
2804
|
+
}
|
|
2805
|
+
const said = readServerRefusal(body);
|
|
2806
|
+
return {
|
|
2807
|
+
collab: null,
|
|
2808
|
+
refusal: {
|
|
2809
|
+
message: said?.reason ?? `Polls and questions could not be read (the server answered ${response.status}).`,
|
|
2810
|
+
remedy: said?.remedy || "Reload the page."
|
|
2811
|
+
}
|
|
2812
|
+
};
|
|
2813
|
+
}
|
|
2814
|
+
return { collab: collabFromState(await response.json(), EMPTY_COLLAB), refusal: null };
|
|
2771
2815
|
}
|
|
2772
2816
|
|
|
2773
2817
|
// src/core/names.ts
|
|
@@ -3840,7 +3884,10 @@ function orderParticipants(participants, activeSpeakers) {
|
|
|
3840
3884
|
}
|
|
3841
3885
|
function computeStage(args) {
|
|
3842
3886
|
const pageSize = Math.max(1, args.pageSize ?? DEFAULT_PAGE_SIZE);
|
|
3843
|
-
const ordered = orderParticipants(
|
|
3887
|
+
const ordered = orderParticipants(
|
|
3888
|
+
args.participants.filter((participant) => !isObserverRole(participant.role)),
|
|
3889
|
+
args.activeSpeakers
|
|
3890
|
+
);
|
|
3844
3891
|
const sharer = ordered.find((participant) => participant.screenSharing) ?? null;
|
|
3845
3892
|
const pinnedParticipant = args.pinned === null ? null : ordered.find((participant) => participant.identity === args.pinned) ?? null;
|
|
3846
3893
|
const spotlit = args.spotlight == null ? null : ordered.find((participant) => participant.identity === args.spotlight) ?? null;
|
|
@@ -5616,7 +5663,8 @@ function createRoomEngine(options) {
|
|
|
5616
5663
|
identity,
|
|
5617
5664
|
...request.meetingId !== void 0 ? { meetingId: request.meetingId } : {},
|
|
5618
5665
|
...request.slug !== void 0 ? { slug: request.slug } : {},
|
|
5619
|
-
...request.breakoutRoomId != null ? { breakoutRoomId: request.breakoutRoomId } : {}
|
|
5666
|
+
...request.breakoutRoomId != null ? { breakoutRoomId: request.breakoutRoomId } : {},
|
|
5667
|
+
...request.observe === true ? { observe: true } : {}
|
|
5620
5668
|
});
|
|
5621
5669
|
current = token;
|
|
5622
5670
|
store.patch({
|
|
@@ -5627,7 +5675,8 @@ function createRoomEngine(options) {
|
|
|
5627
5675
|
standing: token.standing,
|
|
5628
5676
|
canRecord: token.canRecord,
|
|
5629
5677
|
canPublish: token.canPublish,
|
|
5630
|
-
canSubscribe: token.canSubscribe
|
|
5678
|
+
canSubscribe: token.canSubscribe,
|
|
5679
|
+
observersVisibleTo: token.observersVisibleTo ?? "everyone"
|
|
5631
5680
|
}
|
|
5632
5681
|
});
|
|
5633
5682
|
if (token.lobby || !token.canSubscribe) {
|
|
@@ -6127,7 +6176,9 @@ function createInRoomClient(options) {
|
|
|
6127
6176
|
...request.allowChoose !== void 0 ? { allow_choose: request.allowChoose } : {},
|
|
6128
6177
|
...request.minutes !== void 0 ? { minutes: request.minutes } : {},
|
|
6129
6178
|
...request.identity !== void 0 ? { identity: request.identity } : {},
|
|
6130
|
-
...request.roomId !== void 0 ? { room_id: request.roomId } : {}
|
|
6179
|
+
...request.roomId !== void 0 ? { room_id: request.roomId } : {},
|
|
6180
|
+
...request.panel !== void 0 ? { panel: request.panel } : {},
|
|
6181
|
+
...request.section !== void 0 ? { section: request.section } : {}
|
|
6131
6182
|
},
|
|
6132
6183
|
...hdrs !== void 0 ? { headers: hdrs } : {}
|
|
6133
6184
|
});
|