@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/dist/core.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
- if (!response.ok) {
1606
- let body = null;
1607
- try {
1608
- body = await response.json();
1609
- } catch {
1610
- body = null;
1611
- }
1612
- const said = readServerRefusal(body);
1613
- return {
1614
- collab: null,
1615
- refusal: {
1616
- message: said?.reason ?? `Polls and questions could not be read (the server answered ${response.status}).`,
1617
- remedy: said?.remedy || "Reload the page."
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
- return { collab: collabFromState(await response.json(), EMPTY_COLLAB), refusal: null };
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 num2(row, key) {
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: num2(row, "last_sent_sequence"),
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: num2(row, "duration_minutes"),
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: num2(row, "sequence") ?? 0
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: num2(row, "new_duration_minutes"),
1548
+ newDurationMinutes: num(row, "new_duration_minutes"),
1882
1549
  reason: text(row, "reason"),
1883
- calendarSequence: num2(row, "calendar_sequence") ?? 0,
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: num2(meeting, "duration_minutes"),
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: settingsPatch(input.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
- id: requireText(row, "recording_id", operation),
2486
- meetingId: asMeetingId(requireText(row, "meeting_id", operation)),
2487
- meetingTitle: text(row, "meeting_title") ?? "Meeting",
2488
- meetingSlug: requireText(row, "meeting_slug", operation),
2489
- role: role === "host" || role === "cohost" || role === "invitee" ? role : "attendee",
2490
- state: LIBRARY_STATES.includes(state) ? state : "failed",
2491
- title: text(row, "recording_title"),
2492
- fileId: text(row, "file_id"),
2493
- startedAt: text(row, "started_at"),
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
- var SEARCH_SOURCES = [
2503
- "title",
2504
- "summary",
2505
- "decision",
2506
- "action_item",
2507
- "note",
2508
- "transcript"
2509
- ];
2510
- function projectSearchHit(row) {
2511
- const operation = "meet.projectSearchHit";
2512
- const source = text(row, "source");
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
- meetingId: asMeetingId(requireText(row, "meeting_id", operation)),
2515
- meetingTitle: text(row, "meeting_title") ?? "Meeting",
2516
- meetingSlug: requireText(row, "meeting_slug", operation),
2517
- meetingAt: text(row, "meeting_at"),
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 snippetRuns(snippet) {
2527
- const runs = [];
2528
- const pattern = /⟦([^⟧]*)⟧/g;
2529
- let last = 0;
2530
- for (const match of snippet.matchAll(pattern)) {
2531
- const start = match.index ?? 0;
2532
- if (start > last) runs.push({ text: snippet.slice(last, start), hit: false });
2533
- runs.push({ text: match[1] ?? "", hit: true });
2534
- last = start + match[0].length;
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 (last < snippet.length) runs.push({ text: snippet.slice(last), hit: false });
2537
- return runs;
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(args.participants, args.activeSpeakers);
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,