@ai-matrx/meet 0.7.7 → 0.7.8
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 +37 -0
- package/dist/index.cjs +129 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +79 -50
- package/dist/index.d.ts +79 -50
- package/dist/index.js +129 -50
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +827 -701
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +803 -677
- package/dist/react.js.map +1 -1
- package/dist/styles.css +18 -0
- package/package.json +4 -4
package/dist/react.cjs
CHANGED
|
@@ -148,6 +148,7 @@ __export(react_exports, {
|
|
|
148
148
|
attendanceCsv: () => attendanceCsv,
|
|
149
149
|
attendanceReport: () => attendanceReport,
|
|
150
150
|
attendanceTotals: () => attendanceTotals,
|
|
151
|
+
attendeeKey: () => attendeeKey,
|
|
151
152
|
callInviteAction: () => callInviteAction,
|
|
152
153
|
callInviteText: () => callInviteText,
|
|
153
154
|
callStateLabel: () => callStateLabel,
|
|
@@ -251,6 +252,7 @@ __export(react_exports, {
|
|
|
251
252
|
summarizeMeetingRecordRestrictions: () => summarizeMeetingRecordRestrictions,
|
|
252
253
|
transcriptDocument: () => transcriptDocument,
|
|
253
254
|
unavailableFrom: () => unavailableFrom,
|
|
255
|
+
uniqueAttendees: () => uniqueAttendees,
|
|
254
256
|
useAudioLevel: () => useAudioLevel,
|
|
255
257
|
useCalls: () => useCalls,
|
|
256
258
|
useCanModerate: () => useCanModerate,
|
|
@@ -778,6 +780,29 @@ function readText(data) {
|
|
|
778
780
|
}
|
|
779
781
|
return "";
|
|
780
782
|
}
|
|
783
|
+
var SERVER_FAILED_SENTENCE = "The server hit an unexpected problem and nothing was changed.";
|
|
784
|
+
function isRawServerText(value) {
|
|
785
|
+
const text3 = value.trim();
|
|
786
|
+
return /^internal server error\b/i.test(text3) || /^[A-Z][A-Za-z0-9]*(Error|Exception)$/.test(text3) || /^[a-z][a-z0-9]*(_[a-z0-9]+)+$/.test(text3);
|
|
787
|
+
}
|
|
788
|
+
async function refusalFromResponse(response, operation, fallbackRemedy) {
|
|
789
|
+
let body = null;
|
|
790
|
+
try {
|
|
791
|
+
body = await response.json();
|
|
792
|
+
} catch {
|
|
793
|
+
body = null;
|
|
794
|
+
}
|
|
795
|
+
const said = readServerRefusal(body);
|
|
796
|
+
const code = response.status === 403 || response.status === 401 ? "forbidden" : response.status === 404 ? "not-found" : response.status === 409 ? "conflict" : "transport";
|
|
797
|
+
const error = new MeetError(
|
|
798
|
+
code,
|
|
799
|
+
said?.reason ?? SERVER_FAILED_SENTENCE,
|
|
800
|
+
said !== null && said.remedy.length > 0 ? said.remedy : fallbackRemedy
|
|
801
|
+
);
|
|
802
|
+
error.operation = operation;
|
|
803
|
+
error.status = response.status;
|
|
804
|
+
return error;
|
|
805
|
+
}
|
|
781
806
|
function readServerRefusal(body) {
|
|
782
807
|
if (typeof body === "string") {
|
|
783
808
|
return body.trim().length === 0 ? null : { reason: body.trim(), remedy: "" };
|
|
@@ -796,7 +821,8 @@ function readServerRefusal(body) {
|
|
|
796
821
|
return messages.length === 0 ? null : { reason: messages.join("; "), remedy: "" };
|
|
797
822
|
}
|
|
798
823
|
if (typeof detail === "object" && detail !== null) return readServerRefusal(detail);
|
|
799
|
-
const
|
|
824
|
+
const humanOrNull = (value) => typeof value === "string" && value.trim().length > 0 && !isRawServerText(value) ? value.trim() : null;
|
|
825
|
+
const reason = humanOrNull(row["reason"]) ?? humanOrNull(row["message"]) ?? humanOrNull(row["user_message"]) ?? (typeof detail === "string" ? humanOrNull(detail) : null) ?? (typeof row["message"] === "string" || typeof row["error"] === "string" || typeof detail === "string" ? SERVER_FAILED_SENTENCE : null);
|
|
800
826
|
if (reason === null) return null;
|
|
801
827
|
const remedy = typeof row["remedy"] === "string" ? row["remedy"] : "";
|
|
802
828
|
if (remedy.length > 0) return { reason, remedy };
|
|
@@ -1850,6 +1876,7 @@ var EMPTY = {
|
|
|
1850
1876
|
spotlight: null,
|
|
1851
1877
|
moderationNotice: null,
|
|
1852
1878
|
actionNotice: null,
|
|
1879
|
+
privateChatRequest: null,
|
|
1853
1880
|
effects: DEFAULT_EFFECTS,
|
|
1854
1881
|
transcript: [],
|
|
1855
1882
|
notes: [],
|
|
@@ -4039,6 +4066,10 @@ function createRoomEngine(options) {
|
|
|
4039
4066
|
}
|
|
4040
4067
|
},
|
|
4041
4068
|
disconnected(reason) {
|
|
4069
|
+
if (current !== null) {
|
|
4070
|
+
tokens.invalidate(current.roomName);
|
|
4071
|
+
current = null;
|
|
4072
|
+
}
|
|
4042
4073
|
store.patch({ phase: "left" });
|
|
4043
4074
|
options.onLeft?.(reason);
|
|
4044
4075
|
}
|
|
@@ -4341,19 +4372,8 @@ function createInRoomClient(options) {
|
|
|
4341
4372
|
const token = options.resolveRoomToken();
|
|
4342
4373
|
return token === null ? void 0 : { [ROOM_TOKEN_HEADER]: token };
|
|
4343
4374
|
}
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
try {
|
|
4347
|
-
body = await response.json();
|
|
4348
|
-
} catch {
|
|
4349
|
-
body = null;
|
|
4350
|
-
}
|
|
4351
|
-
const said = readServerRefusal(body);
|
|
4352
|
-
return new MeetError(
|
|
4353
|
-
response.status === 403 || response.status === 401 ? "forbidden" : response.status === 404 ? "not-found" : response.status === 409 ? "conflict" : "transport",
|
|
4354
|
-
said?.reason ?? `${operation}: the server answered ${response.status}`,
|
|
4355
|
-
said?.remedy !== void 0 && said.remedy.length > 0 ? said.remedy : remedy
|
|
4356
|
-
);
|
|
4375
|
+
function refusal2(response, operation, remedy) {
|
|
4376
|
+
return refusalFromResponse(response, operation, remedy);
|
|
4357
4377
|
}
|
|
4358
4378
|
return {
|
|
4359
4379
|
async moderate(request) {
|
|
@@ -6313,217 +6333,618 @@ function useGuestRecordAccess(meeting) {
|
|
|
6313
6333
|
// src/react/components.tsx
|
|
6314
6334
|
var import_react4 = require("react");
|
|
6315
6335
|
var import_design_system = require("@ai-matrx/design-system");
|
|
6316
|
-
var
|
|
6336
|
+
var import_format3 = require("@ai-matrx/kit/format");
|
|
6317
6337
|
|
|
6318
|
-
// src/core/
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
if (
|
|
6322
|
-
if (
|
|
6323
|
-
if (
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
function callStateLabel(state, outgoing) {
|
|
6327
|
-
switch (state) {
|
|
6328
|
-
case "dialing":
|
|
6329
|
-
case "ringing":
|
|
6330
|
-
return outgoing ? "Calling\u2026" : "Incoming call";
|
|
6331
|
-
case "connecting":
|
|
6332
|
-
return "Connecting\u2026";
|
|
6333
|
-
case "active":
|
|
6334
|
-
return "In call";
|
|
6335
|
-
case "declined":
|
|
6336
|
-
return outgoing ? "Declined" : "You declined";
|
|
6337
|
-
case "missed":
|
|
6338
|
-
return outgoing ? "No answer" : "Missed call";
|
|
6339
|
-
case "busy":
|
|
6340
|
-
return outgoing ? "On another call" : "You were busy";
|
|
6341
|
-
case "cancelled":
|
|
6342
|
-
return outgoing ? "Cancelled" : "Cancelled by caller";
|
|
6343
|
-
case "ended":
|
|
6344
|
-
return "Call ended";
|
|
6345
|
-
case "failed":
|
|
6346
|
-
return "Call failed";
|
|
6347
|
-
default:
|
|
6348
|
-
return "Call";
|
|
6349
|
-
}
|
|
6338
|
+
// src/core/after.ts
|
|
6339
|
+
var import_format2 = require("@ai-matrx/kit/format");
|
|
6340
|
+
function kindOf(person) {
|
|
6341
|
+
if (person.isAgent) return "assistant";
|
|
6342
|
+
if (person.role === "host") return "host";
|
|
6343
|
+
if (person.role === "cohost") return "cohost";
|
|
6344
|
+
if (person.role === "guest") return person.userId !== null ? "signed-in guest" : "guest";
|
|
6345
|
+
return "member";
|
|
6350
6346
|
}
|
|
6351
|
-
function
|
|
6352
|
-
|
|
6347
|
+
function ms(iso) {
|
|
6348
|
+
if (iso === null) return null;
|
|
6349
|
+
const at = new Date(iso).getTime();
|
|
6350
|
+
return Number.isNaN(at) ? null : at;
|
|
6353
6351
|
}
|
|
6354
|
-
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
return
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
strokeLinejoin: "round",
|
|
6369
|
-
"aria-hidden": "true",
|
|
6370
|
-
focusable: "false",
|
|
6371
|
-
...props,
|
|
6372
|
-
children
|
|
6352
|
+
function attendeeKey(person, names = {}) {
|
|
6353
|
+
if (person.userId !== null) return `user:${person.userId}`;
|
|
6354
|
+
if (person.isAgent) return `agent:${person.identity}`;
|
|
6355
|
+
const name = displayNameFor(names, person.identity, person.displayName).trim().toLowerCase();
|
|
6356
|
+
return name.length > 0 ? `guest-name:${name}` : `identity:${person.identity}`;
|
|
6357
|
+
}
|
|
6358
|
+
function uniqueAttendees(attendees, names = {}) {
|
|
6359
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
6360
|
+
for (const person of attendees) {
|
|
6361
|
+
const key = attendeeKey(person, names);
|
|
6362
|
+
const kept = byKey.get(key);
|
|
6363
|
+
if (kept === void 0) {
|
|
6364
|
+
byKey.set(key, person);
|
|
6365
|
+
continue;
|
|
6373
6366
|
}
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6367
|
+
const keptJoin = ms(kept.joinedAt);
|
|
6368
|
+
const join = ms(person.joinedAt);
|
|
6369
|
+
if (join !== null && (keptJoin === null || join < keptJoin)) byKey.set(key, person);
|
|
6370
|
+
}
|
|
6371
|
+
return [...byKey.values()];
|
|
6372
|
+
}
|
|
6373
|
+
var KIND_RANK = {
|
|
6374
|
+
host: 0,
|
|
6375
|
+
cohost: 1,
|
|
6376
|
+
member: 2,
|
|
6377
|
+
"signed-in guest": 3,
|
|
6378
|
+
guest: 4,
|
|
6379
|
+
assistant: 5
|
|
6380
|
+
};
|
|
6381
|
+
function coveredMs(intervals) {
|
|
6382
|
+
const sorted = [...intervals].sort((a, b) => a[0] - b[0]);
|
|
6383
|
+
let total = 0;
|
|
6384
|
+
let from = -Infinity;
|
|
6385
|
+
let to = -Infinity;
|
|
6386
|
+
for (const [start, end] of sorted) {
|
|
6387
|
+
if (start > to) {
|
|
6388
|
+
if (to > from) total += to - from;
|
|
6389
|
+
from = start;
|
|
6390
|
+
to = end;
|
|
6391
|
+
} else if (end > to) {
|
|
6392
|
+
to = end;
|
|
6393
|
+
}
|
|
6394
|
+
}
|
|
6395
|
+
if (to > from) total += to - from;
|
|
6396
|
+
return total;
|
|
6391
6397
|
}
|
|
6392
|
-
function
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6398
|
+
function attendanceReport(meeting, attendees, names = {}) {
|
|
6399
|
+
const end = ms(meeting.endedAt);
|
|
6400
|
+
const perJoin = attendees.map((person) => {
|
|
6401
|
+
const joined = ms(person.joinedAt);
|
|
6402
|
+
const left = ms(person.leftAt);
|
|
6403
|
+
const until = left ?? end;
|
|
6404
|
+
const duration = joined !== null && until !== null && until >= joined ? until - joined : null;
|
|
6405
|
+
return {
|
|
6406
|
+
id: person.id,
|
|
6407
|
+
identity: person.identity,
|
|
6408
|
+
name: displayNameFor(names, person.identity, person.displayName),
|
|
6409
|
+
userId: person.userId,
|
|
6410
|
+
kind: kindOf(person),
|
|
6411
|
+
joinedAt: person.joinedAt,
|
|
6412
|
+
leftAt: person.leftAt,
|
|
6413
|
+
durationMs: duration,
|
|
6414
|
+
durationToEnd: duration !== null && left === null,
|
|
6415
|
+
admission: person.admissionState,
|
|
6416
|
+
joins: 1
|
|
6417
|
+
};
|
|
6418
|
+
});
|
|
6419
|
+
const groups = /* @__PURE__ */ new Map();
|
|
6420
|
+
attendees.forEach((person, index) => {
|
|
6421
|
+
const key = attendeeKey(person, names);
|
|
6422
|
+
const group = groups.get(key) ?? { rows: [], people: [] };
|
|
6423
|
+
group.rows.push(perJoin[index]);
|
|
6424
|
+
group.people.push(person);
|
|
6425
|
+
groups.set(key, group);
|
|
6426
|
+
});
|
|
6427
|
+
const rows = [...groups.values()].map(({ rows: joins }) => {
|
|
6428
|
+
if (joins.length === 1) return joins[0];
|
|
6429
|
+
const came = joins.filter((row) => row.joinedAt !== null);
|
|
6430
|
+
const first = [...came].sort((a, b) => (ms(a.joinedAt) ?? 0) - (ms(b.joinedAt) ?? 0))[0] ?? joins[0];
|
|
6431
|
+
const kind = joins.reduce(
|
|
6432
|
+
(best, row) => KIND_RANK[row.kind] < KIND_RANK[best] ? row.kind : best,
|
|
6433
|
+
first.kind
|
|
6434
|
+
);
|
|
6435
|
+
const open = came.some((row) => row.leftAt === null);
|
|
6436
|
+
const lastLeave = came.reduce((latest, row) => {
|
|
6437
|
+
const left = ms(row.leftAt);
|
|
6438
|
+
return left !== null && (latest === null || left > latest) ? left : latest;
|
|
6439
|
+
}, null);
|
|
6440
|
+
const intervals = came.flatMap((row) => {
|
|
6441
|
+
const joined = ms(row.joinedAt);
|
|
6442
|
+
return joined !== null && row.durationMs !== null ? [[joined, joined + row.durationMs]] : [];
|
|
6443
|
+
});
|
|
6444
|
+
return {
|
|
6445
|
+
...first,
|
|
6446
|
+
kind,
|
|
6447
|
+
leftAt: open ? null : lastLeave === null ? null : new Date(lastLeave).toISOString(),
|
|
6448
|
+
durationMs: intervals.length === 0 ? null : coveredMs(intervals),
|
|
6449
|
+
durationToEnd: came.some((row) => row.durationToEnd),
|
|
6450
|
+
joins: came.length === 0 ? joins.length : came.length
|
|
6451
|
+
};
|
|
6452
|
+
});
|
|
6453
|
+
const rank = KIND_RANK;
|
|
6454
|
+
return rows.sort((a, b) => {
|
|
6455
|
+
if (rank[a.kind] !== rank[b.kind]) return rank[a.kind] - rank[b.kind];
|
|
6456
|
+
return (ms(a.joinedAt) ?? Number.MAX_SAFE_INTEGER) - (ms(b.joinedAt) ?? Number.MAX_SAFE_INTEGER);
|
|
6457
|
+
});
|
|
6397
6458
|
}
|
|
6398
|
-
function
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6459
|
+
function attendanceTotals(rows) {
|
|
6460
|
+
const humans = rows.filter((row) => row.kind !== "assistant");
|
|
6461
|
+
const attended = humans.filter((row) => row.joinedAt !== null);
|
|
6462
|
+
const timed = attended.filter((row) => row.durationMs !== null);
|
|
6463
|
+
return {
|
|
6464
|
+
people: attended.length,
|
|
6465
|
+
guests: attended.filter((row) => row.kind === "guest" || row.kind === "signed-in guest").length,
|
|
6466
|
+
neverAdmitted: humans.filter((row) => row.joinedAt === null).length,
|
|
6467
|
+
averageMs: timed.length === 0 ? null : Math.round(timed.reduce((sum, row) => sum + (row.durationMs ?? 0), 0) / timed.length)
|
|
6468
|
+
};
|
|
6404
6469
|
}
|
|
6405
|
-
function
|
|
6406
|
-
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 13V8m0 0-2.5 2.5M12 8l2.5 2.5" })
|
|
6410
|
-
] });
|
|
6470
|
+
function csvCell(value) {
|
|
6471
|
+
if (value === null) return "";
|
|
6472
|
+
const text3 = String(value);
|
|
6473
|
+
return /[",\n\r]/.test(text3) ? `"${text3.replace(/"/g, '""')}"` : text3;
|
|
6411
6474
|
}
|
|
6412
|
-
|
|
6413
|
-
|
|
6475
|
+
var ATTENDANCE_CSV_HEADER = [
|
|
6476
|
+
"Meeting",
|
|
6477
|
+
"Meeting started",
|
|
6478
|
+
"Name",
|
|
6479
|
+
"Attended as",
|
|
6480
|
+
"Joined",
|
|
6481
|
+
"Left",
|
|
6482
|
+
"Minutes in the meeting",
|
|
6483
|
+
"Admission"
|
|
6484
|
+
];
|
|
6485
|
+
function attendanceCsv(reports) {
|
|
6486
|
+
const lines = [ATTENDANCE_CSV_HEADER.join(",")];
|
|
6487
|
+
for (const { meeting, rows } of reports) {
|
|
6488
|
+
for (const row of rows) {
|
|
6489
|
+
lines.push(
|
|
6490
|
+
[
|
|
6491
|
+
meeting.title,
|
|
6492
|
+
meeting.startedAt ?? meeting.scheduledFor,
|
|
6493
|
+
row.name,
|
|
6494
|
+
row.kind,
|
|
6495
|
+
row.joinedAt,
|
|
6496
|
+
row.leftAt,
|
|
6497
|
+
row.durationMs === null ? null : Math.round(row.durationMs / 6e3) / 10,
|
|
6498
|
+
row.admission
|
|
6499
|
+
].map(csvCell).join(",")
|
|
6500
|
+
);
|
|
6501
|
+
}
|
|
6502
|
+
}
|
|
6503
|
+
return `${lines.join("\r\n")}\r
|
|
6504
|
+
`;
|
|
6414
6505
|
}
|
|
6415
|
-
function
|
|
6416
|
-
|
|
6417
|
-
|
|
6418
|
-
|
|
6419
|
-
|
|
6420
|
-
|
|
6506
|
+
function recordingOffsetMs(at, recording) {
|
|
6507
|
+
if (recording === null || recording.state !== "available") return null;
|
|
6508
|
+
const start = ms(recording.startedAt);
|
|
6509
|
+
const moment = ms(at);
|
|
6510
|
+
if (start === null || moment === null || moment < start) return null;
|
|
6511
|
+
const end = ms(recording.endedAt);
|
|
6512
|
+
if (end !== null && moment > end) return null;
|
|
6513
|
+
return moment - start;
|
|
6421
6514
|
}
|
|
6422
|
-
function
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
|
|
6428
|
-
|
|
6515
|
+
function clockPosition(offsetMs) {
|
|
6516
|
+
const total = Math.max(0, Math.floor(offsetMs / 1e3));
|
|
6517
|
+
const h = Math.floor(total / 3600);
|
|
6518
|
+
const m = Math.floor(total % 3600 / 60);
|
|
6519
|
+
const s = total % 60;
|
|
6520
|
+
const ss = String(s).padStart(2, "0");
|
|
6521
|
+
return h > 0 ? `${h}:${String(m).padStart(2, "0")}:${ss}` : `${m}:${ss}`;
|
|
6429
6522
|
}
|
|
6430
|
-
function
|
|
6431
|
-
|
|
6523
|
+
function searchTranscript(segments, query, names = {}) {
|
|
6524
|
+
const needle = fold(query.trim());
|
|
6525
|
+
if (needle.length === 0) return [];
|
|
6526
|
+
const out = [];
|
|
6527
|
+
for (const segment of segments) {
|
|
6528
|
+
const hay = fold(segment.text);
|
|
6529
|
+
const ranges = [];
|
|
6530
|
+
let from = 0;
|
|
6531
|
+
for (; ; ) {
|
|
6532
|
+
const at = hay.indexOf(needle, from);
|
|
6533
|
+
if (at < 0) break;
|
|
6534
|
+
ranges.push([at, at + needle.length]);
|
|
6535
|
+
from = at + needle.length;
|
|
6536
|
+
}
|
|
6537
|
+
const speaker = fold(displayNameFor(names, segment.identity, segment.speaker));
|
|
6538
|
+
if (ranges.length > 0 || speaker.includes(needle)) {
|
|
6539
|
+
out.push({ segmentId: segment.id, ranges });
|
|
6540
|
+
}
|
|
6541
|
+
}
|
|
6542
|
+
return out;
|
|
6432
6543
|
}
|
|
6433
|
-
function
|
|
6434
|
-
return
|
|
6435
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }),
|
|
6436
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "9", cy: "7", r: "4" }),
|
|
6437
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75" })
|
|
6438
|
-
] });
|
|
6544
|
+
function fold(value) {
|
|
6545
|
+
return value.normalize("NFD").replace(/[̀-ͯ]/g, (mark) => mark.length === 1 ? "" : mark).toLowerCase();
|
|
6439
6546
|
}
|
|
6440
|
-
function
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
}
|
|
6449
|
-
function LockIcon(props) {
|
|
6450
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6451
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: "4", y: "10", width: "16", height: "11", rx: "2" }),
|
|
6452
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M8 10V7a4 4 0 0 1 8 0v3" })
|
|
6453
|
-
] });
|
|
6454
|
-
}
|
|
6455
|
-
function LayoutIcon(props) {
|
|
6456
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6457
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
|
|
6458
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M3 9h18M9 21V9" })
|
|
6459
|
-
] });
|
|
6547
|
+
function clockOfDay(iso, options) {
|
|
6548
|
+
const at = new Date(iso);
|
|
6549
|
+
if (Number.isNaN(at.getTime())) return "";
|
|
6550
|
+
return at.toLocaleTimeString(options.locale, {
|
|
6551
|
+
hour: "numeric",
|
|
6552
|
+
minute: "2-digit",
|
|
6553
|
+
second: "2-digit",
|
|
6554
|
+
...options.timeZone !== void 0 ? { timeZone: options.timeZone } : {}
|
|
6555
|
+
});
|
|
6460
6556
|
}
|
|
6461
|
-
function
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6557
|
+
function vttStamp(offsetMs) {
|
|
6558
|
+
const total = Math.max(0, Math.round(offsetMs));
|
|
6559
|
+
const h = Math.floor(total / 36e5);
|
|
6560
|
+
const m = Math.floor(total % 36e5 / 6e4);
|
|
6561
|
+
const s = Math.floor(total % 6e4 / 1e3);
|
|
6562
|
+
const milli = total % 1e3;
|
|
6563
|
+
return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}.${String(milli).padStart(3, "0")}`;
|
|
6466
6564
|
}
|
|
6467
|
-
function
|
|
6468
|
-
|
|
6565
|
+
function transcriptDocument(bundle, format, options = {}) {
|
|
6566
|
+
const names = options.names ?? bundle.names;
|
|
6567
|
+
const lines = bundle.transcript.filter((line) => line.text.trim().length > 0);
|
|
6568
|
+
const speaker = (line) => displayNameFor(names, line.identity, line.speaker);
|
|
6569
|
+
if (format === "vtt") {
|
|
6570
|
+
const zeroIso = bundle.recording?.state === "available" && bundle.recording.startedAt !== null ? bundle.recording.startedAt : bundle.meeting.startedAt ?? lines[0]?.startedAt ?? null;
|
|
6571
|
+
const zero = ms(zeroIso) ?? 0;
|
|
6572
|
+
const cues = ["WEBVTT", ""];
|
|
6573
|
+
lines.forEach((line, index) => {
|
|
6574
|
+
const start = (ms(line.startedAt) ?? zero) - zero;
|
|
6575
|
+
if (start < 0) return;
|
|
6576
|
+
const next = lines[index + 1];
|
|
6577
|
+
const nextStart = next !== void 0 ? (ms(next.startedAt) ?? zero) - zero : start + 4e3;
|
|
6578
|
+
const end = Math.max(start + 500, Math.min(nextStart, start + 1e4));
|
|
6579
|
+
cues.push(`${vttStamp(start)} --> ${vttStamp(end)}`);
|
|
6580
|
+
cues.push(`<v ${speaker(line).replace(/[<>]/g, "")}>${line.text.replace(/-->/g, "->")}`);
|
|
6581
|
+
cues.push("");
|
|
6582
|
+
});
|
|
6583
|
+
return cues.join("\n");
|
|
6584
|
+
}
|
|
6585
|
+
const out = [];
|
|
6586
|
+
const title = bundle.meeting.title;
|
|
6587
|
+
out.push(format === "md" ? `# ${title} \u2014 transcript` : `${title} \u2014 transcript`);
|
|
6588
|
+
out.push("");
|
|
6589
|
+
let last = null;
|
|
6590
|
+
for (const line of lines) {
|
|
6591
|
+
if (line.identity !== last) {
|
|
6592
|
+
if (last !== null) out.push("");
|
|
6593
|
+
const who = speaker(line);
|
|
6594
|
+
const clock = clockOfDay(line.startedAt, options);
|
|
6595
|
+
out.push(format === "md" ? `**${who}** \xB7 ${clock}` : `${who} (${clock})`);
|
|
6596
|
+
last = line.identity;
|
|
6597
|
+
}
|
|
6598
|
+
out.push(line.text.trim());
|
|
6599
|
+
}
|
|
6600
|
+
if (lines.length === 0) out.push("No transcript was captured for this meeting.");
|
|
6601
|
+
return `${out.join("\n")}
|
|
6602
|
+
`;
|
|
6469
6603
|
}
|
|
6470
|
-
function
|
|
6471
|
-
|
|
6604
|
+
function bullet(note) {
|
|
6605
|
+
const owner = note.assigneeDisplayName !== null ? ` \u2014 ${note.assigneeDisplayName}` : "";
|
|
6606
|
+
return `- ${note.text.trim()}${owner}`;
|
|
6472
6607
|
}
|
|
6473
|
-
function
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6608
|
+
function notesDocument(bundle, options = {}) {
|
|
6609
|
+
const out = [`# ${bundle.meeting.title}`, ""];
|
|
6610
|
+
if (options.when) out.push(`_${options.when}_`, "");
|
|
6611
|
+
const people = uniqueAttendees(
|
|
6612
|
+
bundle.attendees.filter((person) => !person.isAgent && person.joinedAt !== null),
|
|
6613
|
+
bundle.names
|
|
6614
|
+
).map((person) => displayNameFor(bundle.names, person.identity, person.displayName));
|
|
6615
|
+
if (people.length > 0) out.push(`**Attended:** ${people.join(", ")}`, "");
|
|
6616
|
+
out.push("## Summary", "", bundle.summary?.text.trim() || "No summary was written.", "");
|
|
6617
|
+
out.push("## Decisions", "");
|
|
6618
|
+
out.push(...bundle.decisions.length > 0 ? bundle.decisions.map(bullet) : ["None recorded."], "");
|
|
6619
|
+
out.push("## Action items", "");
|
|
6620
|
+
out.push(
|
|
6621
|
+
...bundle.actionItems.length > 0 ? bundle.actionItems.map(bullet) : ["None recorded."],
|
|
6622
|
+
""
|
|
6623
|
+
);
|
|
6624
|
+
if (options.link) out.push(`[Open the meeting record](${options.link})`, "");
|
|
6625
|
+
return out.join("\n");
|
|
6478
6626
|
}
|
|
6479
|
-
function
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6627
|
+
function meetingLength(meeting) {
|
|
6628
|
+
const start = ms(meeting.startedAt);
|
|
6629
|
+
const end = ms(meeting.endedAt);
|
|
6630
|
+
if (start === null || end === null || end < start) return null;
|
|
6631
|
+
return (0, import_format2.formatDurationMs)(end - start, { style: "long" });
|
|
6484
6632
|
}
|
|
6485
|
-
function
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6633
|
+
async function loadMeetingChat(api, meetingId, roomToken = null) {
|
|
6634
|
+
const operation = "meet.loadMeetingChat";
|
|
6635
|
+
let response;
|
|
6636
|
+
try {
|
|
6637
|
+
response = await api.request({
|
|
6638
|
+
path: `${MEET_ROUTES.chat}?meeting_id=${encodeURIComponent(meetingId)}`,
|
|
6639
|
+
method: "GET",
|
|
6640
|
+
operation,
|
|
6641
|
+
requireAuth: roomToken === null,
|
|
6642
|
+
...roomToken !== null ? { headers: { [ROOM_TOKEN_HEADER]: roomToken } } : {}
|
|
6643
|
+
});
|
|
6644
|
+
} catch (error) {
|
|
6645
|
+
return {
|
|
6646
|
+
messages: [],
|
|
6647
|
+
refusal: {
|
|
6648
|
+
message: `The chat could not be read (${error.message}).`,
|
|
6649
|
+
remedy: error.remedy ?? "Reload the page."
|
|
6650
|
+
}
|
|
6651
|
+
};
|
|
6652
|
+
}
|
|
6653
|
+
if (!response.ok) {
|
|
6654
|
+
let body = null;
|
|
6655
|
+
try {
|
|
6656
|
+
body = await response.json();
|
|
6657
|
+
} catch {
|
|
6658
|
+
body = null;
|
|
6659
|
+
}
|
|
6660
|
+
const said = readServerRefusal(body);
|
|
6661
|
+
return {
|
|
6662
|
+
messages: [],
|
|
6663
|
+
refusal: {
|
|
6664
|
+
message: said?.reason ?? `The chat could not be read (the server answered ${response.status}).`,
|
|
6665
|
+
remedy: said?.remedy || "Reload the page."
|
|
6666
|
+
}
|
|
6667
|
+
};
|
|
6668
|
+
}
|
|
6669
|
+
const payload = await response.json();
|
|
6670
|
+
const rows = Array.isArray(payload.messages) ? payload.messages : [];
|
|
6671
|
+
return {
|
|
6672
|
+
messages: rows.map(
|
|
6673
|
+
(row) => typeof row === "object" && row !== null ? chatFromRow(row) : null
|
|
6674
|
+
).filter((message) => message !== null),
|
|
6675
|
+
refusal: null
|
|
6676
|
+
};
|
|
6492
6677
|
}
|
|
6493
|
-
function
|
|
6494
|
-
return
|
|
6495
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "12", cy: "12", r: "1" }),
|
|
6496
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "19", cy: "12", r: "1" }),
|
|
6497
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "5", cy: "12", r: "1" })
|
|
6498
|
-
] });
|
|
6678
|
+
function refusalOf(response, operation) {
|
|
6679
|
+
return refusalFromResponse(response, operation, "Nothing was sent. Try again.");
|
|
6499
6680
|
}
|
|
6500
|
-
function
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6681
|
+
function asRecipient(row) {
|
|
6682
|
+
const sources = Array.isArray(row["sources"]) ? row["sources"] : [];
|
|
6683
|
+
return {
|
|
6684
|
+
key: String(row["key"] ?? ""),
|
|
6685
|
+
name: String(row["name"] ?? ""),
|
|
6686
|
+
email: typeof row["email"] === "string" ? row["email"] : null,
|
|
6687
|
+
userId: typeof row["user_id"] === "string" ? row["user_id"] : null,
|
|
6688
|
+
sources: sources.filter((s) => s === "invitee" || s === "attendee"),
|
|
6689
|
+
reachable: row["reachable"] !== false
|
|
6690
|
+
};
|
|
6505
6691
|
}
|
|
6506
|
-
function
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6692
|
+
async function loadFollowUpDraft(api, meetingId) {
|
|
6693
|
+
const operation = "meet.loadFollowUpDraft";
|
|
6694
|
+
const response = await api.request({
|
|
6695
|
+
path: meetingPath(MEET_ROUTES.meetingFollowUp, meetingId),
|
|
6696
|
+
method: "GET",
|
|
6697
|
+
requireAuth: true,
|
|
6698
|
+
operation
|
|
6699
|
+
});
|
|
6700
|
+
if (!response.ok) throw await refusalOf(response, operation);
|
|
6701
|
+
const body = await response.json();
|
|
6702
|
+
const last = body["last_sent"];
|
|
6703
|
+
return {
|
|
6704
|
+
subject: String(body["subject"] ?? ""),
|
|
6705
|
+
body: String(body["body"] ?? ""),
|
|
6706
|
+
recipients: (Array.isArray(body["recipients"]) ? body["recipients"] : []).map(
|
|
6707
|
+
(row) => asRecipient(row)
|
|
6708
|
+
),
|
|
6709
|
+
wrapUpWritten: body["wrap_up_written"] === true,
|
|
6710
|
+
lastSent: last && typeof last["at"] === "string" ? { at: last["at"], count: typeof last["count"] === "number" ? last["count"] : 0 } : null
|
|
6711
|
+
};
|
|
6511
6712
|
}
|
|
6512
|
-
function
|
|
6513
|
-
|
|
6713
|
+
async function sendFollowUp(api, meetingId, input) {
|
|
6714
|
+
const operation = "meet.sendFollowUp";
|
|
6715
|
+
const response = await api.request({
|
|
6716
|
+
path: meetingPath(MEET_ROUTES.meetingFollowUp, meetingId),
|
|
6717
|
+
method: "POST",
|
|
6718
|
+
requireAuth: true,
|
|
6719
|
+
operation,
|
|
6720
|
+
body: {
|
|
6721
|
+
subject: input.subject,
|
|
6722
|
+
body: input.body,
|
|
6723
|
+
recipient_keys: [...input.recipientKeys],
|
|
6724
|
+
dry_run: input.dryRun === true
|
|
6725
|
+
}
|
|
6726
|
+
});
|
|
6727
|
+
if (!response.ok) throw await refusalOf(response, operation);
|
|
6728
|
+
const body = await response.json();
|
|
6729
|
+
return {
|
|
6730
|
+
dryRun: body["dry_run"] === true,
|
|
6731
|
+
queued: Array.isArray(body["queued"]) ? body["queued"] : [],
|
|
6732
|
+
skipped: Array.isArray(body["skipped"]) ? body["skipped"].map((row) => ({
|
|
6733
|
+
key: String(row["key"] ?? ""),
|
|
6734
|
+
reason: String(row["reason"] ?? "")
|
|
6735
|
+
})) : []
|
|
6736
|
+
};
|
|
6514
6737
|
}
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
] }
|
|
6738
|
+
|
|
6739
|
+
// src/core/format.ts
|
|
6740
|
+
function participantSummary(participants) {
|
|
6741
|
+
const names = participants.filter((p) => !p.isLocal).map((p) => p.displayName);
|
|
6742
|
+
if (names.length === 0) return "Just you";
|
|
6743
|
+
if (names.length === 1) return names[0] ?? "";
|
|
6744
|
+
if (names.length === 2) return `${names[0]} and ${names[1]}`;
|
|
6745
|
+
return `${names[0]}, ${names[1]} and ${names.length - 2} ${names.length - 2 === 1 ? "other" : "others"}`;
|
|
6522
6746
|
}
|
|
6523
|
-
function
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6747
|
+
function callStateLabel(state, outgoing) {
|
|
6748
|
+
switch (state) {
|
|
6749
|
+
case "dialing":
|
|
6750
|
+
case "ringing":
|
|
6751
|
+
return outgoing ? "Calling\u2026" : "Incoming call";
|
|
6752
|
+
case "connecting":
|
|
6753
|
+
return "Connecting\u2026";
|
|
6754
|
+
case "active":
|
|
6755
|
+
return "In call";
|
|
6756
|
+
case "declined":
|
|
6757
|
+
return outgoing ? "Declined" : "You declined";
|
|
6758
|
+
case "missed":
|
|
6759
|
+
return outgoing ? "No answer" : "Missed call";
|
|
6760
|
+
case "busy":
|
|
6761
|
+
return outgoing ? "On another call" : "You were busy";
|
|
6762
|
+
case "cancelled":
|
|
6763
|
+
return outgoing ? "Cancelled" : "Cancelled by caller";
|
|
6764
|
+
case "ended":
|
|
6765
|
+
return "Call ended";
|
|
6766
|
+
case "failed":
|
|
6767
|
+
return "Call failed";
|
|
6768
|
+
default:
|
|
6769
|
+
return "Call";
|
|
6770
|
+
}
|
|
6771
|
+
}
|
|
6772
|
+
function countLabel(count2, singular, plural = `${singular}s`) {
|
|
6773
|
+
return `${count2} ${count2 === 1 ? singular : plural}`;
|
|
6774
|
+
}
|
|
6775
|
+
|
|
6776
|
+
// src/react/icons.tsx
|
|
6777
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
6778
|
+
function Icon({ children, ...props }) {
|
|
6779
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
6780
|
+
"svg",
|
|
6781
|
+
{
|
|
6782
|
+
width: "20",
|
|
6783
|
+
height: "20",
|
|
6784
|
+
viewBox: "0 0 24 24",
|
|
6785
|
+
fill: "none",
|
|
6786
|
+
stroke: "currentColor",
|
|
6787
|
+
strokeWidth: "1.75",
|
|
6788
|
+
strokeLinecap: "round",
|
|
6789
|
+
strokeLinejoin: "round",
|
|
6790
|
+
"aria-hidden": "true",
|
|
6791
|
+
focusable: "false",
|
|
6792
|
+
...props,
|
|
6793
|
+
children
|
|
6794
|
+
}
|
|
6795
|
+
);
|
|
6796
|
+
}
|
|
6797
|
+
function MicIcon(props) {
|
|
6798
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6799
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" }),
|
|
6800
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
|
|
6801
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 19v3" })
|
|
6802
|
+
] });
|
|
6803
|
+
}
|
|
6804
|
+
function MicOffIcon(props) {
|
|
6805
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6806
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M2 2l20 20" }),
|
|
6807
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M9 9v3a3 3 0 0 0 5.12 2.12" }),
|
|
6808
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M15 9.34V5a3 3 0 0 0-5.94-.6" }),
|
|
6809
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M19 10v2a7 7 0 0 1-.11 1.23M5 10v2a7 7 0 0 0 11 5.66" }),
|
|
6810
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 19v3" })
|
|
6811
|
+
] });
|
|
6812
|
+
}
|
|
6813
|
+
function CameraIcon(props) {
|
|
6814
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6815
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m23 7-7 5 7 5V7Z" }),
|
|
6816
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: "1", y: "5", width: "15", height: "14", rx: "2" })
|
|
6817
|
+
] });
|
|
6818
|
+
}
|
|
6819
|
+
function CameraOffIcon(props) {
|
|
6820
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6821
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M2 2l20 20" }),
|
|
6822
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M10.66 5H14a2 2 0 0 1 2 2v3.34l1 1L23 7v10" }),
|
|
6823
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M16 16a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h2" })
|
|
6824
|
+
] });
|
|
6825
|
+
}
|
|
6826
|
+
function ScreenShareIcon(props) {
|
|
6827
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6828
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2" }),
|
|
6829
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M8 21h8M12 17v4" }),
|
|
6830
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 13V8m0 0-2.5 2.5M12 8l2.5 2.5" })
|
|
6831
|
+
] });
|
|
6832
|
+
}
|
|
6833
|
+
function PhoneIcon(props) {
|
|
6834
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Icon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6A19.79 19.79 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.9.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92Z" }) });
|
|
6835
|
+
}
|
|
6836
|
+
function PhoneOffIcon(props) {
|
|
6837
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6838
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M2 2l20 20" }),
|
|
6839
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M10.68 13.31a16 16 0 0 0 3.41 2.6l1.27-1.27a2 2 0 0 1 2.11-.45c.9.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.42 19.42 0 0 1-3.33-2.67" }),
|
|
6840
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M5.53 5.53A19.79 19.79 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91" })
|
|
6841
|
+
] });
|
|
6842
|
+
}
|
|
6843
|
+
function HandIcon(props) {
|
|
6844
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6845
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M18 11V6a2 2 0 0 0-4 0v5" }),
|
|
6846
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M14 10V4a2 2 0 0 0-4 0v7" }),
|
|
6847
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M10 10.5V6a2 2 0 0 0-4 0v8" }),
|
|
6848
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2a8 8 0 0 1-8-8v-1a2 2 0 1 1 4 0" })
|
|
6849
|
+
] });
|
|
6850
|
+
}
|
|
6851
|
+
function ChatIcon(props) {
|
|
6852
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Icon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2Z" }) });
|
|
6853
|
+
}
|
|
6854
|
+
function PeopleIcon(props) {
|
|
6855
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6856
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }),
|
|
6857
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "9", cy: "7", r: "4" }),
|
|
6858
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75" })
|
|
6859
|
+
] });
|
|
6860
|
+
}
|
|
6861
|
+
function RecordIcon(props) {
|
|
6862
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Icon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "12", cy: "12", r: "8", fill: "currentColor", stroke: "none" }) });
|
|
6863
|
+
}
|
|
6864
|
+
function SparklesIcon(props) {
|
|
6865
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6866
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 3l1.9 4.6L18.5 9.5l-4.6 1.9L12 16l-1.9-4.6L5.5 9.5l4.6-1.9L12 3Z" }),
|
|
6867
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M19 15l.9 2.1 2.1.9-2.1.9-.9 2.1-.9-2.1-2.1-.9 2.1-.9L19 15Z" })
|
|
6868
|
+
] });
|
|
6869
|
+
}
|
|
6870
|
+
function LockIcon(props) {
|
|
6871
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6872
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: "4", y: "10", width: "16", height: "11", rx: "2" }),
|
|
6873
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M8 10V7a4 4 0 0 1 8 0v3" })
|
|
6874
|
+
] });
|
|
6875
|
+
}
|
|
6876
|
+
function LayoutIcon(props) {
|
|
6877
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6878
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
|
|
6879
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M3 9h18M9 21V9" })
|
|
6880
|
+
] });
|
|
6881
|
+
}
|
|
6882
|
+
function SettingsIcon(props) {
|
|
6883
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6884
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "12", cy: "12", r: "3" }),
|
|
6885
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.6a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z" })
|
|
6886
|
+
] });
|
|
6887
|
+
}
|
|
6888
|
+
function CheckIcon(props) {
|
|
6889
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Icon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M20 6 9 17l-5-5" }) });
|
|
6890
|
+
}
|
|
6891
|
+
function CloseIcon(props) {
|
|
6892
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Icon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M18 6 6 18M6 6l12 12" }) });
|
|
6893
|
+
}
|
|
6894
|
+
function PinIcon(props) {
|
|
6895
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6896
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 17v5" }),
|
|
6897
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M9 2h6l-1 6 3.5 3.5V14H6.5v-2.5L10 8 9 2Z" })
|
|
6898
|
+
] });
|
|
6899
|
+
}
|
|
6900
|
+
function WifiLowIcon(props) {
|
|
6901
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6902
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 20h.01" }),
|
|
6903
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M8.5 16.5a5 5 0 0 1 7 0" })
|
|
6904
|
+
] });
|
|
6905
|
+
}
|
|
6906
|
+
function SmileIcon(props) {
|
|
6907
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6908
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
|
|
6909
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M8 14s1.5 2 4 2 4-2 4-2" }),
|
|
6910
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "9", x2: "9.01", y1: "9", y2: "9" }),
|
|
6911
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "15", x2: "15.01", y1: "9", y2: "9" })
|
|
6912
|
+
] });
|
|
6913
|
+
}
|
|
6914
|
+
function MoreIcon(props) {
|
|
6915
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6916
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "12", cy: "12", r: "1" }),
|
|
6917
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "19", cy: "12", r: "1" }),
|
|
6918
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "5", cy: "12", r: "1" })
|
|
6919
|
+
] });
|
|
6920
|
+
}
|
|
6921
|
+
function SearchIcon(props) {
|
|
6922
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6923
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "11", cy: "11", r: "8" }),
|
|
6924
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m21 21-4.3-4.3" })
|
|
6925
|
+
] });
|
|
6926
|
+
}
|
|
6927
|
+
function KeyboardIcon(props) {
|
|
6928
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6929
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M10 8h.01M12 12h.01M14 8h.01M16 12h.01M18 8h.01M6 8h.01M7 16h10M8 12h.01" }),
|
|
6930
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { width: "20", height: "16", x: "2", y: "4", rx: "2" })
|
|
6931
|
+
] });
|
|
6932
|
+
}
|
|
6933
|
+
function SpotlightIcon(props) {
|
|
6934
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Icon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 2 15 8.5 22 9.3 17 14 18.2 21 12 17.6 5.8 21 7 14 2 9.3 9 8.5Z" }) });
|
|
6935
|
+
}
|
|
6936
|
+
function SignalIcon({ bars, ...props }) {
|
|
6937
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6938
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M4 20v-2", opacity: bars >= 1 ? 1 : 0.3 }),
|
|
6939
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M10 20v-6", opacity: bars >= 2 ? 1 : 0.3 }),
|
|
6940
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M16 20V9", opacity: bars >= 3 ? 1 : 0.3 }),
|
|
6941
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M22 20V4", opacity: bars >= 3 ? 1 : 0.3 })
|
|
6942
|
+
] });
|
|
6943
|
+
}
|
|
6944
|
+
function SpeakerIcon(props) {
|
|
6945
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Icon, { ...props, children: [
|
|
6946
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M11 5 6 9H2v6h4l5 4V5Z" }),
|
|
6947
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M15.54 8.46a5 5 0 0 1 0 7.07" }),
|
|
6527
6948
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M19.07 4.93a10 10 0 0 1 0 14.14" })
|
|
6528
6949
|
] });
|
|
6529
6950
|
}
|
|
@@ -6553,7 +6974,7 @@ function Avatar({
|
|
|
6553
6974
|
url,
|
|
6554
6975
|
size = 40
|
|
6555
6976
|
}) {
|
|
6556
|
-
const tint = (0,
|
|
6977
|
+
const tint = (0, import_format3.avatarPaletteIndex)(name);
|
|
6557
6978
|
if (url != null && url.length > 0) {
|
|
6558
6979
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
6559
6980
|
"img",
|
|
@@ -6578,7 +6999,7 @@ function Avatar({
|
|
|
6578
6999
|
background: `var(--mx-meet-avatar-${tint})`
|
|
6579
7000
|
},
|
|
6580
7001
|
"aria-hidden": "true",
|
|
6581
|
-
children: (0,
|
|
7002
|
+
children: (0, import_format3.getInitials)(name)
|
|
6582
7003
|
}
|
|
6583
7004
|
);
|
|
6584
7005
|
}
|
|
@@ -6763,6 +7184,15 @@ function ControlBar({ onLeave }) {
|
|
|
6763
7184
|
const micUnavailable = useLocalMedia().microphone.unavailable;
|
|
6764
7185
|
const unread = useUnreadChat(panel === "chat");
|
|
6765
7186
|
const toggle = (next) => setPanel(panel === next ? "none" : next);
|
|
7187
|
+
const privateChatAt = snapshot?.privateChatRequest?.at ?? null;
|
|
7188
|
+
const meetStore = useMeetHost()?.store ?? null;
|
|
7189
|
+
(0, import_react4.useEffect)(() => {
|
|
7190
|
+
const request = meetStore?.snapshot().privateChatRequest ?? null;
|
|
7191
|
+
if (request === null) return;
|
|
7192
|
+
setChatTo(request.to);
|
|
7193
|
+
setPanel("chat");
|
|
7194
|
+
meetStore?.patch({ privateChatRequest: null });
|
|
7195
|
+
}, [privateChatAt, meetStore]);
|
|
6766
7196
|
useMeetShortcuts({
|
|
6767
7197
|
mic: () => void room.toggleMicrophone(),
|
|
6768
7198
|
camera: () => void room.toggleCamera(),
|
|
@@ -7002,7 +7432,12 @@ function Popover({
|
|
|
7002
7432
|
placement = "up"
|
|
7003
7433
|
}) {
|
|
7004
7434
|
const ref = (0, import_react4.useRef)(null);
|
|
7005
|
-
const [style, setStyle] = (0, import_react4.useState)({
|
|
7435
|
+
const [style, setStyle] = (0, import_react4.useState)({
|
|
7436
|
+
position: "fixed",
|
|
7437
|
+
top: 0,
|
|
7438
|
+
left: 0,
|
|
7439
|
+
visibility: "hidden"
|
|
7440
|
+
});
|
|
7006
7441
|
(0, import_react4.useLayoutEffect)(() => {
|
|
7007
7442
|
const element = ref.current;
|
|
7008
7443
|
const anchor = element?.parentElement ?? null;
|
|
@@ -7018,14 +7453,35 @@ function Popover({
|
|
|
7018
7453
|
);
|
|
7019
7454
|
const fitsBelow = rect.bottom + gutter + height <= window.innerHeight;
|
|
7020
7455
|
const fitsAbove = rect.top - gutter - height >= 0;
|
|
7456
|
+
if (!fitsBelow && !fitsAbove) {
|
|
7457
|
+
const top = Math.max(gutter, window.innerHeight - height - gutter);
|
|
7458
|
+
setStyle({
|
|
7459
|
+
position: "fixed",
|
|
7460
|
+
left,
|
|
7461
|
+
top,
|
|
7462
|
+
maxHeight: window.innerHeight - top - gutter,
|
|
7463
|
+
overflowY: "auto"
|
|
7464
|
+
});
|
|
7465
|
+
return;
|
|
7466
|
+
}
|
|
7021
7467
|
const down = placement === "down" ? fitsBelow || !fitsAbove : !fitsAbove && fitsBelow;
|
|
7022
7468
|
setStyle(
|
|
7023
7469
|
down ? { position: "fixed", left, top: rect.bottom + gutter } : { position: "fixed", left, bottom: window.innerHeight - rect.top + gutter }
|
|
7024
7470
|
);
|
|
7025
7471
|
};
|
|
7026
7472
|
place();
|
|
7473
|
+
const frame = requestAnimationFrame(place);
|
|
7474
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(() => place());
|
|
7475
|
+
observer?.observe(document.body);
|
|
7476
|
+
observer?.observe(element);
|
|
7027
7477
|
window.addEventListener("resize", place);
|
|
7028
|
-
|
|
7478
|
+
window.addEventListener("scroll", place, true);
|
|
7479
|
+
return () => {
|
|
7480
|
+
cancelAnimationFrame(frame);
|
|
7481
|
+
observer?.disconnect();
|
|
7482
|
+
window.removeEventListener("resize", place);
|
|
7483
|
+
window.removeEventListener("scroll", place, true);
|
|
7484
|
+
};
|
|
7029
7485
|
}, [placement]);
|
|
7030
7486
|
(0, import_react4.useEffect)(() => {
|
|
7031
7487
|
const onKey = (event) => {
|
|
@@ -7402,11 +7858,15 @@ function PersonMenu({
|
|
|
7402
7858
|
const pinned = snapshot?.pinned === participant.identity;
|
|
7403
7859
|
const spotlit = snapshot?.spotlight === participant.identity;
|
|
7404
7860
|
const hasAccount = participant.userId !== null;
|
|
7861
|
+
const [refused, setRefused] = (0, import_react4.useState)(false);
|
|
7405
7862
|
const act = (request) => {
|
|
7863
|
+
setRefused(false);
|
|
7406
7864
|
void controls.run(request).then((result) => {
|
|
7407
7865
|
if (result !== null) onClose();
|
|
7866
|
+
else setRefused(true);
|
|
7408
7867
|
});
|
|
7409
7868
|
};
|
|
7869
|
+
const refusal2 = refused && controls.notice?.failed === true ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.ErrorBox, { as: "p", className: "mx-meet__error", message: controls.notice.text, operation: "Change this participant", origin: "meet/components", children: controls.notice.text }) : null;
|
|
7410
7870
|
if (mode === "rename" || mode === "report") {
|
|
7411
7871
|
const renaming = mode === "rename";
|
|
7412
7872
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Popover, { label: renaming ? "Rename" : "Report", onClose, placement, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
@@ -7444,7 +7904,7 @@ function PersonMenu({
|
|
|
7444
7904
|
}
|
|
7445
7905
|
)
|
|
7446
7906
|
] }),
|
|
7447
|
-
|
|
7907
|
+
refusal2,
|
|
7448
7908
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mx-meet__menu-actions", children: [
|
|
7449
7909
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mx-meet__link", onClick: () => setMode("menu"), children: "Back" }),
|
|
7450
7910
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "submit", className: "mx-meet__send", disabled: text3.trim().length === 0 || controls.busy, children: renaming ? "Rename" : "Report" })
|
|
@@ -7457,6 +7917,7 @@ function PersonMenu({
|
|
|
7457
7917
|
const removing = mode === "remove";
|
|
7458
7918
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Popover, { label: removing ? "Remove" : "Make host", onClose, placement, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mx-meet__menu-form", children: [
|
|
7459
7919
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mx-meet__confirm-text", children: removing ? `Remove ${participant.displayName}? They leave immediately and cannot rejoin this meeting.` : `Make ${participant.displayName} the host? They get every host control and own this meeting. You stay on as a co-host.` }),
|
|
7920
|
+
refusal2,
|
|
7460
7921
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mx-meet__menu-actions", children: [
|
|
7461
7922
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mx-meet__link", onClick: () => setMode("menu"), children: "Cancel" }),
|
|
7462
7923
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -7487,11 +7948,15 @@ function PersonMenu({
|
|
|
7487
7948
|
]
|
|
7488
7949
|
}
|
|
7489
7950
|
),
|
|
7490
|
-
!self && !participant.isAgent && onMessage !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
7951
|
+
!self && !participant.isAgent && (onMessage !== void 0 || host !== null) ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
7491
7952
|
MenuItem,
|
|
7492
7953
|
{
|
|
7493
7954
|
onSelect: () => {
|
|
7494
|
-
onMessage(participant.identity);
|
|
7955
|
+
if (onMessage !== void 0) onMessage(participant.identity);
|
|
7956
|
+
else
|
|
7957
|
+
host?.store.patch({
|
|
7958
|
+
privateChatRequest: { to: participant.identity, at: Date.now() }
|
|
7959
|
+
});
|
|
7495
7960
|
onClose();
|
|
7496
7961
|
},
|
|
7497
7962
|
children: [
|
|
@@ -8118,7 +8583,7 @@ function PreJoinBody({
|
|
|
8118
8583
|
microphone,
|
|
8119
8584
|
...meetingId !== void 0 ? { meetingId } : {},
|
|
8120
8585
|
...slug !== void 0 ? { slug } : {}
|
|
8121
|
-
}).then(() => onJoined?.()).finally(() => setJoining(false));
|
|
8586
|
+
}).then(() => onJoined?.()).catch(() => void 0).finally(() => setJoining(false));
|
|
8122
8587
|
},
|
|
8123
8588
|
children: joining ? "Joining\u2026" : "Join now"
|
|
8124
8589
|
}
|
|
@@ -8254,7 +8719,7 @@ function MeetingRoomBody({
|
|
|
8254
8719
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h1", { className: "mx-meet__title", children: snapshot?.meeting?.title ?? "Meeting" }),
|
|
8255
8720
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "mx-meet__meta", children: [
|
|
8256
8721
|
participantSummary(snapshot?.participants ?? []),
|
|
8257
|
-
elapsed > 0 ? ` \xB7 ${(0,
|
|
8722
|
+
elapsed > 0 ? ` \xB7 ${(0, import_format3.formatDurationMs)(elapsed)}` : ""
|
|
8258
8723
|
] }),
|
|
8259
8724
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RecordingIndicator, {}),
|
|
8260
8725
|
snapshot?.locked === true ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "mx-meet__badge", children: [
|
|
@@ -8560,7 +9025,10 @@ function MeetingRecordBody({
|
|
|
8560
9025
|
const blocks = groupTranscript(bundle.transcript, bundle.names);
|
|
8561
9026
|
const notice = recordingNotice(bundle.recording);
|
|
8562
9027
|
const fileId = playableRecordingFileId(bundle.recording);
|
|
8563
|
-
const attended =
|
|
9028
|
+
const attended = uniqueAttendees(
|
|
9029
|
+
bundle.attendees.filter((person) => person.admissionState !== "denied"),
|
|
9030
|
+
bundle.names
|
|
9031
|
+
);
|
|
8564
9032
|
const restrictionNotices = summarizeMeetingRecordRestrictions(bundle.restrictions);
|
|
8565
9033
|
const guestFinishedMeeting = host.identity.userId === null && meeting.endedAt !== null;
|
|
8566
9034
|
const everyRecordPartRefused = ["attendance", "notes", "transcript", "recording"].every(
|
|
@@ -8869,514 +9337,172 @@ function RecordingPlayerBody({ fileId, host }) {
|
|
|
8869
9337
|
const failure = thrown;
|
|
8870
9338
|
setError({
|
|
8871
9339
|
message: failure.message ?? "The recording could not be loaded.",
|
|
8872
|
-
remedy: failure.remedy ?? PLAYBACK_RETRY_REMEDY
|
|
8873
|
-
});
|
|
8874
|
-
} finally {
|
|
8875
|
-
setLoading(false);
|
|
8876
|
-
}
|
|
8877
|
-
})();
|
|
8878
|
-
},
|
|
8879
|
-
children: loading ? "Loading the recording\u2026" : "Play the recording"
|
|
8880
|
-
}
|
|
8881
|
-
)
|
|
8882
|
-
] });
|
|
8883
|
-
}
|
|
8884
|
-
function clockOf(iso) {
|
|
8885
|
-
const at = new Date(iso);
|
|
8886
|
-
if (Number.isNaN(at.getTime())) return "";
|
|
8887
|
-
return at.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
|
|
8888
|
-
}
|
|
8889
|
-
function MeetingList({ baseUrl }) {
|
|
8890
|
-
const host = useMeetHost();
|
|
8891
|
-
const list = useMeetings();
|
|
8892
|
-
if (host === null) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(InertNotice, { what: "Your meetings" });
|
|
8893
|
-
if (list.failure !== null) {
|
|
8894
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system.ErrorBox, { as: "div", className: "mx-meet__empty", error: list.failure, operation: "List your meetings", origin: "meet/components", children: [
|
|
8895
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mx-meet__empty-title", children: "Your meetings could not be listed" }),
|
|
8896
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mx-meet__empty-body", children: list.failure.message }),
|
|
8897
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mx-meet__empty-body", children: list.failure.remedy })
|
|
8898
|
-
] });
|
|
8899
|
-
}
|
|
8900
|
-
if (list.loading) {
|
|
8901
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mx-meet__empty", role: "status", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mx-meet__empty-title", children: "Loading your meetings\u2026" }) });
|
|
8902
|
-
}
|
|
8903
|
-
if (list.meetings.length === 0) {
|
|
8904
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mx-meet__empty", role: "status", children: [
|
|
8905
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mx-meet__empty-title", children: "No meetings yet" }),
|
|
8906
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mx-meet__empty-body", children: "Create one above. Its link works before, during and after the meeting \u2014 afterwards it opens the record." })
|
|
8907
|
-
] });
|
|
8908
|
-
}
|
|
8909
|
-
const origin = baseUrl ?? (typeof window === "undefined" ? "" : window.location.origin);
|
|
8910
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: "mx-meet-list", children: list.meetings.map((meeting) => {
|
|
8911
|
-
const ended = meeting.endedAt !== null;
|
|
8912
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { className: "mx-meet-list__row", children: [
|
|
8913
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mx-meet-list__main", children: [
|
|
8914
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "mx-meet-list__title", children: [
|
|
8915
|
-
meeting.title,
|
|
8916
|
-
ended ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "mx-meet__badge", children: "Ended" }) : null
|
|
8917
|
-
] }),
|
|
8918
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "mx-meet-list__when", children: meetingWhen(meeting) })
|
|
8919
|
-
] }),
|
|
8920
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { className: "mx-meet-list__action", href: meetingLink(origin, meeting.slug), children: ended ? "Open the record" : "Join" })
|
|
8921
|
-
] }, meeting.id);
|
|
8922
|
-
}) });
|
|
8923
|
-
}
|
|
8924
|
-
|
|
8925
|
-
// src/core/invitations.ts
|
|
8926
|
-
var CALL_INVITE_KIND = "meet.call-invite";
|
|
8927
|
-
var CALL_INVITE_VERSION = 1;
|
|
8928
|
-
function callInviteAction(invite) {
|
|
8929
|
-
return {
|
|
8930
|
-
kind: CALL_INVITE_KIND,
|
|
8931
|
-
version: CALL_INVITE_VERSION,
|
|
8932
|
-
payload: {
|
|
8933
|
-
invite_id: invite.id,
|
|
8934
|
-
room_name: invite.roomName,
|
|
8935
|
-
mode: invite.mode,
|
|
8936
|
-
caller_name: invite.callerName,
|
|
8937
|
-
expires_at: invite.expiresAt
|
|
8938
|
-
}
|
|
8939
|
-
};
|
|
8940
|
-
}
|
|
8941
|
-
function callInviteText(invite) {
|
|
8942
|
-
return invite.mode === "video" ? `${invite.callerName} started a video call` : `${invite.callerName} started an audio call`;
|
|
8943
|
-
}
|
|
8944
|
-
function createCallInviteHandler(options) {
|
|
8945
|
-
const now = options.now ?? (() => Date.now());
|
|
8946
|
-
return {
|
|
8947
|
-
kind: CALL_INVITE_KIND,
|
|
8948
|
-
versions: [CALL_INVITE_VERSION],
|
|
8949
|
-
choices: (payload) => {
|
|
8950
|
-
if (Date.parse(payload.expires_at) < now()) return [];
|
|
8951
|
-
return [
|
|
8952
|
-
{ id: "join", label: payload.mode === "video" ? "Join video" : "Join call", tone: "primary" },
|
|
8953
|
-
{ id: "decline", label: "Decline", tone: "neutral" }
|
|
8954
|
-
];
|
|
8955
|
-
},
|
|
8956
|
-
summarize: (payload) => payload.mode === "video" ? `${payload.caller_name} started a video call` : `${payload.caller_name} started an audio call`,
|
|
8957
|
-
execute: async (payload, context) => {
|
|
8958
|
-
const settledAt = new Date(now()).toISOString();
|
|
8959
|
-
const inviteId = asCallId(payload.invite_id);
|
|
8960
|
-
const pending = await options.repository.pendingInvites(asUserId(String(context.actorId)));
|
|
8961
|
-
const live = pending.find((invite) => invite.id === inviteId) ?? null;
|
|
8962
|
-
if (live === null) {
|
|
8963
|
-
return {
|
|
8964
|
-
kind: CALL_INVITE_KIND,
|
|
8965
|
-
messageId: context.messageId,
|
|
8966
|
-
actorId: context.actorId,
|
|
8967
|
-
outcome: "unavailable",
|
|
8968
|
-
label: "This call has ended",
|
|
8969
|
-
settledAt,
|
|
8970
|
-
detail: "The invite is no longer ringing \u2014 it was answered elsewhere, cancelled, or it timed out. The chips are replaced by the outcome rather than left clickable."
|
|
8971
|
-
};
|
|
8972
|
-
}
|
|
8973
|
-
if (context.choice === "decline") {
|
|
8974
|
-
await options.calls.decline(inviteId);
|
|
8975
|
-
return {
|
|
8976
|
-
kind: CALL_INVITE_KIND,
|
|
8977
|
-
messageId: context.messageId,
|
|
8978
|
-
actorId: context.actorId,
|
|
8979
|
-
outcome: "declined",
|
|
8980
|
-
label: "Declined",
|
|
8981
|
-
settledAt
|
|
8982
|
-
};
|
|
8983
|
-
}
|
|
8984
|
-
const accepted = await options.calls.accept(inviteId, live.mode);
|
|
8985
|
-
await options.onJoin(accepted);
|
|
8986
|
-
return {
|
|
8987
|
-
kind: CALL_INVITE_KIND,
|
|
8988
|
-
messageId: context.messageId,
|
|
8989
|
-
actorId: context.actorId,
|
|
8990
|
-
outcome: "applied",
|
|
8991
|
-
label: "Joined",
|
|
8992
|
-
settledAt
|
|
8993
|
-
};
|
|
8994
|
-
}
|
|
8995
|
-
};
|
|
8996
|
-
}
|
|
8997
|
-
var MEETING_INVITE_KIND = "meet.meeting-invite";
|
|
8998
|
-
var MEETING_INVITE_VERSION = 1;
|
|
8999
|
-
function meetingInviteAction(payload) {
|
|
9000
|
-
return { kind: MEETING_INVITE_KIND, version: MEETING_INVITE_VERSION, payload };
|
|
9001
|
-
}
|
|
9002
|
-
function createMeetingInviteHandler(options) {
|
|
9003
|
-
const now = options.now ?? (() => Date.now());
|
|
9004
|
-
return {
|
|
9005
|
-
kind: MEETING_INVITE_KIND,
|
|
9006
|
-
versions: [MEETING_INVITE_VERSION],
|
|
9007
|
-
// A DURABLE LINK NEVER EXPIRES (R3) — the chip stays useful after the
|
|
9008
|
-
// meeting too, because that is when people go looking for the notes.
|
|
9009
|
-
choices: () => [{ id: "open", label: "Open meeting", tone: "primary" }],
|
|
9010
|
-
summarize: (payload) => payload.scheduled_for === null ? payload.title : `${payload.title} \u2014 ${payload.scheduled_for}`,
|
|
9011
|
-
execute: async (payload, context) => {
|
|
9012
|
-
if (payload.slug.length === 0) {
|
|
9013
|
-
throw new MeetError(
|
|
9014
|
-
"invalid-response",
|
|
9015
|
-
"meet.meeting-invite: the payload carries no slug",
|
|
9016
|
-
"A meeting invitation without a durable slug cannot be opened. Fix the sender; never synthesize a link on the receiving side."
|
|
9017
|
-
);
|
|
9018
|
-
}
|
|
9019
|
-
await options.onOpen(payload);
|
|
9020
|
-
return {
|
|
9021
|
-
kind: MEETING_INVITE_KIND,
|
|
9022
|
-
messageId: context.messageId,
|
|
9023
|
-
actorId: context.actorId,
|
|
9024
|
-
outcome: "applied",
|
|
9025
|
-
label: "Opened",
|
|
9026
|
-
settledAt: new Date(now()).toISOString()
|
|
9027
|
-
};
|
|
9028
|
-
}
|
|
9029
|
-
};
|
|
9030
|
-
}
|
|
9031
|
-
|
|
9032
|
-
// src/core/after.ts
|
|
9033
|
-
var import_format4 = require("@ai-matrx/kit/format");
|
|
9034
|
-
function kindOf(person) {
|
|
9035
|
-
if (person.isAgent) return "assistant";
|
|
9036
|
-
if (person.role === "host") return "host";
|
|
9037
|
-
if (person.role === "cohost") return "cohost";
|
|
9038
|
-
if (person.role === "guest") return person.userId !== null ? "signed-in guest" : "guest";
|
|
9039
|
-
return "member";
|
|
9040
|
-
}
|
|
9041
|
-
function ms(iso) {
|
|
9042
|
-
if (iso === null) return null;
|
|
9043
|
-
const at = new Date(iso).getTime();
|
|
9044
|
-
return Number.isNaN(at) ? null : at;
|
|
9045
|
-
}
|
|
9046
|
-
function attendanceReport(meeting, attendees, names = {}) {
|
|
9047
|
-
const end = ms(meeting.endedAt);
|
|
9048
|
-
const rows = attendees.map((person) => {
|
|
9049
|
-
const joined = ms(person.joinedAt);
|
|
9050
|
-
const left = ms(person.leftAt);
|
|
9051
|
-
const until = left ?? end;
|
|
9052
|
-
const duration = joined !== null && until !== null && until >= joined ? until - joined : null;
|
|
9053
|
-
return {
|
|
9054
|
-
id: person.id,
|
|
9055
|
-
identity: person.identity,
|
|
9056
|
-
name: displayNameFor(names, person.identity, person.displayName),
|
|
9057
|
-
userId: person.userId,
|
|
9058
|
-
kind: kindOf(person),
|
|
9059
|
-
joinedAt: person.joinedAt,
|
|
9060
|
-
leftAt: person.leftAt,
|
|
9061
|
-
durationMs: duration,
|
|
9062
|
-
durationToEnd: duration !== null && left === null,
|
|
9063
|
-
admission: person.admissionState
|
|
9064
|
-
};
|
|
9065
|
-
});
|
|
9066
|
-
const rank = {
|
|
9067
|
-
host: 0,
|
|
9068
|
-
cohost: 1,
|
|
9069
|
-
member: 2,
|
|
9070
|
-
"signed-in guest": 3,
|
|
9071
|
-
guest: 4,
|
|
9072
|
-
assistant: 5
|
|
9073
|
-
};
|
|
9074
|
-
return rows.sort((a, b) => {
|
|
9075
|
-
if (rank[a.kind] !== rank[b.kind]) return rank[a.kind] - rank[b.kind];
|
|
9076
|
-
return (ms(a.joinedAt) ?? Number.MAX_SAFE_INTEGER) - (ms(b.joinedAt) ?? Number.MAX_SAFE_INTEGER);
|
|
9077
|
-
});
|
|
9078
|
-
}
|
|
9079
|
-
function attendanceTotals(rows) {
|
|
9080
|
-
const humans = rows.filter((row) => row.kind !== "assistant");
|
|
9081
|
-
const attended = humans.filter((row) => row.joinedAt !== null);
|
|
9082
|
-
const timed = attended.filter((row) => row.durationMs !== null);
|
|
9083
|
-
return {
|
|
9084
|
-
people: attended.length,
|
|
9085
|
-
guests: attended.filter((row) => row.kind === "guest" || row.kind === "signed-in guest").length,
|
|
9086
|
-
neverAdmitted: humans.filter((row) => row.joinedAt === null).length,
|
|
9087
|
-
averageMs: timed.length === 0 ? null : Math.round(timed.reduce((sum, row) => sum + (row.durationMs ?? 0), 0) / timed.length)
|
|
9088
|
-
};
|
|
9089
|
-
}
|
|
9090
|
-
function csvCell(value) {
|
|
9091
|
-
if (value === null) return "";
|
|
9092
|
-
const text3 = String(value);
|
|
9093
|
-
return /[",\n\r]/.test(text3) ? `"${text3.replace(/"/g, '""')}"` : text3;
|
|
9094
|
-
}
|
|
9095
|
-
var ATTENDANCE_CSV_HEADER = [
|
|
9096
|
-
"Meeting",
|
|
9097
|
-
"Meeting started",
|
|
9098
|
-
"Name",
|
|
9099
|
-
"Attended as",
|
|
9100
|
-
"Joined",
|
|
9101
|
-
"Left",
|
|
9102
|
-
"Minutes in the meeting",
|
|
9103
|
-
"Admission"
|
|
9104
|
-
];
|
|
9105
|
-
function attendanceCsv(reports) {
|
|
9106
|
-
const lines = [ATTENDANCE_CSV_HEADER.join(",")];
|
|
9107
|
-
for (const { meeting, rows } of reports) {
|
|
9108
|
-
for (const row of rows) {
|
|
9109
|
-
lines.push(
|
|
9110
|
-
[
|
|
9111
|
-
meeting.title,
|
|
9112
|
-
meeting.startedAt ?? meeting.scheduledFor,
|
|
9113
|
-
row.name,
|
|
9114
|
-
row.kind,
|
|
9115
|
-
row.joinedAt,
|
|
9116
|
-
row.leftAt,
|
|
9117
|
-
row.durationMs === null ? null : Math.round(row.durationMs / 6e3) / 10,
|
|
9118
|
-
row.admission
|
|
9119
|
-
].map(csvCell).join(",")
|
|
9120
|
-
);
|
|
9121
|
-
}
|
|
9122
|
-
}
|
|
9123
|
-
return `${lines.join("\r\n")}\r
|
|
9124
|
-
`;
|
|
9125
|
-
}
|
|
9126
|
-
function recordingOffsetMs(at, recording) {
|
|
9127
|
-
if (recording === null || recording.state !== "available") return null;
|
|
9128
|
-
const start = ms(recording.startedAt);
|
|
9129
|
-
const moment = ms(at);
|
|
9130
|
-
if (start === null || moment === null || moment < start) return null;
|
|
9131
|
-
const end = ms(recording.endedAt);
|
|
9132
|
-
if (end !== null && moment > end) return null;
|
|
9133
|
-
return moment - start;
|
|
9134
|
-
}
|
|
9135
|
-
function clockPosition(offsetMs) {
|
|
9136
|
-
const total = Math.max(0, Math.floor(offsetMs / 1e3));
|
|
9137
|
-
const h = Math.floor(total / 3600);
|
|
9138
|
-
const m = Math.floor(total % 3600 / 60);
|
|
9139
|
-
const s = total % 60;
|
|
9140
|
-
const ss = String(s).padStart(2, "0");
|
|
9141
|
-
return h > 0 ? `${h}:${String(m).padStart(2, "0")}:${ss}` : `${m}:${ss}`;
|
|
9142
|
-
}
|
|
9143
|
-
function searchTranscript(segments, query, names = {}) {
|
|
9144
|
-
const needle = fold(query.trim());
|
|
9145
|
-
if (needle.length === 0) return [];
|
|
9146
|
-
const out = [];
|
|
9147
|
-
for (const segment of segments) {
|
|
9148
|
-
const hay = fold(segment.text);
|
|
9149
|
-
const ranges = [];
|
|
9150
|
-
let from = 0;
|
|
9151
|
-
for (; ; ) {
|
|
9152
|
-
const at = hay.indexOf(needle, from);
|
|
9153
|
-
if (at < 0) break;
|
|
9154
|
-
ranges.push([at, at + needle.length]);
|
|
9155
|
-
from = at + needle.length;
|
|
9156
|
-
}
|
|
9157
|
-
const speaker = fold(displayNameFor(names, segment.identity, segment.speaker));
|
|
9158
|
-
if (ranges.length > 0 || speaker.includes(needle)) {
|
|
9159
|
-
out.push({ segmentId: segment.id, ranges });
|
|
9160
|
-
}
|
|
9161
|
-
}
|
|
9162
|
-
return out;
|
|
9163
|
-
}
|
|
9164
|
-
function fold(value) {
|
|
9165
|
-
return value.normalize("NFD").replace(/[̀-ͯ]/g, (mark) => mark.length === 1 ? "" : mark).toLowerCase();
|
|
9166
|
-
}
|
|
9167
|
-
function clockOfDay(iso, options) {
|
|
9168
|
-
const at = new Date(iso);
|
|
9169
|
-
if (Number.isNaN(at.getTime())) return "";
|
|
9170
|
-
return at.toLocaleTimeString(options.locale, {
|
|
9171
|
-
hour: "numeric",
|
|
9172
|
-
minute: "2-digit",
|
|
9173
|
-
second: "2-digit",
|
|
9174
|
-
...options.timeZone !== void 0 ? { timeZone: options.timeZone } : {}
|
|
9175
|
-
});
|
|
9176
|
-
}
|
|
9177
|
-
function vttStamp(offsetMs) {
|
|
9178
|
-
const total = Math.max(0, Math.round(offsetMs));
|
|
9179
|
-
const h = Math.floor(total / 36e5);
|
|
9180
|
-
const m = Math.floor(total % 36e5 / 6e4);
|
|
9181
|
-
const s = Math.floor(total % 6e4 / 1e3);
|
|
9182
|
-
const milli = total % 1e3;
|
|
9183
|
-
return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}.${String(milli).padStart(3, "0")}`;
|
|
9184
|
-
}
|
|
9185
|
-
function transcriptDocument(bundle, format, options = {}) {
|
|
9186
|
-
const names = options.names ?? bundle.names;
|
|
9187
|
-
const lines = bundle.transcript.filter((line) => line.text.trim().length > 0);
|
|
9188
|
-
const speaker = (line) => displayNameFor(names, line.identity, line.speaker);
|
|
9189
|
-
if (format === "vtt") {
|
|
9190
|
-
const zeroIso = bundle.recording?.state === "available" && bundle.recording.startedAt !== null ? bundle.recording.startedAt : bundle.meeting.startedAt ?? lines[0]?.startedAt ?? null;
|
|
9191
|
-
const zero = ms(zeroIso) ?? 0;
|
|
9192
|
-
const cues = ["WEBVTT", ""];
|
|
9193
|
-
lines.forEach((line, index) => {
|
|
9194
|
-
const start = (ms(line.startedAt) ?? zero) - zero;
|
|
9195
|
-
if (start < 0) return;
|
|
9196
|
-
const next = lines[index + 1];
|
|
9197
|
-
const nextStart = next !== void 0 ? (ms(next.startedAt) ?? zero) - zero : start + 4e3;
|
|
9198
|
-
const end = Math.max(start + 500, Math.min(nextStart, start + 1e4));
|
|
9199
|
-
cues.push(`${vttStamp(start)} --> ${vttStamp(end)}`);
|
|
9200
|
-
cues.push(`<v ${speaker(line).replace(/[<>]/g, "")}>${line.text.replace(/-->/g, "->")}`);
|
|
9201
|
-
cues.push("");
|
|
9202
|
-
});
|
|
9203
|
-
return cues.join("\n");
|
|
9204
|
-
}
|
|
9205
|
-
const out = [];
|
|
9206
|
-
const title = bundle.meeting.title;
|
|
9207
|
-
out.push(format === "md" ? `# ${title} \u2014 transcript` : `${title} \u2014 transcript`);
|
|
9208
|
-
out.push("");
|
|
9209
|
-
let last = null;
|
|
9210
|
-
for (const line of lines) {
|
|
9211
|
-
if (line.identity !== last) {
|
|
9212
|
-
if (last !== null) out.push("");
|
|
9213
|
-
const who = speaker(line);
|
|
9214
|
-
const clock = clockOfDay(line.startedAt, options);
|
|
9215
|
-
out.push(format === "md" ? `**${who}** \xB7 ${clock}` : `${who} (${clock})`);
|
|
9216
|
-
last = line.identity;
|
|
9217
|
-
}
|
|
9218
|
-
out.push(line.text.trim());
|
|
9219
|
-
}
|
|
9220
|
-
if (lines.length === 0) out.push("No transcript was captured for this meeting.");
|
|
9221
|
-
return `${out.join("\n")}
|
|
9222
|
-
`;
|
|
9223
|
-
}
|
|
9224
|
-
function bullet(note) {
|
|
9225
|
-
const owner = note.assigneeDisplayName !== null ? ` \u2014 ${note.assigneeDisplayName}` : "";
|
|
9226
|
-
return `- ${note.text.trim()}${owner}`;
|
|
9227
|
-
}
|
|
9228
|
-
function notesDocument(bundle, options = {}) {
|
|
9229
|
-
const out = [`# ${bundle.meeting.title}`, ""];
|
|
9230
|
-
if (options.when) out.push(`_${options.when}_`, "");
|
|
9231
|
-
const people = bundle.attendees.filter((person) => !person.isAgent && person.joinedAt !== null).map((person) => displayNameFor(bundle.names, person.identity, person.displayName));
|
|
9232
|
-
if (people.length > 0) out.push(`**Attended:** ${people.join(", ")}`, "");
|
|
9233
|
-
out.push("## Summary", "", bundle.summary?.text.trim() || "No summary was written.", "");
|
|
9234
|
-
out.push("## Decisions", "");
|
|
9235
|
-
out.push(...bundle.decisions.length > 0 ? bundle.decisions.map(bullet) : ["None recorded."], "");
|
|
9236
|
-
out.push("## Action items", "");
|
|
9237
|
-
out.push(
|
|
9238
|
-
...bundle.actionItems.length > 0 ? bundle.actionItems.map(bullet) : ["None recorded."],
|
|
9239
|
-
""
|
|
9240
|
-
);
|
|
9241
|
-
if (options.link) out.push(`[Open the meeting record](${options.link})`, "");
|
|
9242
|
-
return out.join("\n");
|
|
9340
|
+
remedy: failure.remedy ?? PLAYBACK_RETRY_REMEDY
|
|
9341
|
+
});
|
|
9342
|
+
} finally {
|
|
9343
|
+
setLoading(false);
|
|
9344
|
+
}
|
|
9345
|
+
})();
|
|
9346
|
+
},
|
|
9347
|
+
children: loading ? "Loading the recording\u2026" : "Play the recording"
|
|
9348
|
+
}
|
|
9349
|
+
)
|
|
9350
|
+
] });
|
|
9243
9351
|
}
|
|
9244
|
-
function
|
|
9245
|
-
const
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
return (0, import_format4.formatDurationMs)(end - start, { style: "long" });
|
|
9352
|
+
function clockOf(iso) {
|
|
9353
|
+
const at = new Date(iso);
|
|
9354
|
+
if (Number.isNaN(at.getTime())) return "";
|
|
9355
|
+
return at.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
|
|
9249
9356
|
}
|
|
9250
|
-
|
|
9251
|
-
const
|
|
9252
|
-
|
|
9253
|
-
|
|
9254
|
-
|
|
9255
|
-
|
|
9256
|
-
|
|
9257
|
-
|
|
9258
|
-
|
|
9259
|
-
|
|
9260
|
-
});
|
|
9261
|
-
} catch (error) {
|
|
9262
|
-
return {
|
|
9263
|
-
messages: [],
|
|
9264
|
-
refusal: {
|
|
9265
|
-
message: `The chat could not be read (${error.message}).`,
|
|
9266
|
-
remedy: error.remedy ?? "Reload the page."
|
|
9267
|
-
}
|
|
9268
|
-
};
|
|
9357
|
+
function MeetingList({ baseUrl }) {
|
|
9358
|
+
const host = useMeetHost();
|
|
9359
|
+
const list = useMeetings();
|
|
9360
|
+
if (host === null) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(InertNotice, { what: "Your meetings" });
|
|
9361
|
+
if (list.failure !== null) {
|
|
9362
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system.ErrorBox, { as: "div", className: "mx-meet__empty", error: list.failure, operation: "List your meetings", origin: "meet/components", children: [
|
|
9363
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mx-meet__empty-title", children: "Your meetings could not be listed" }),
|
|
9364
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mx-meet__empty-body", children: list.failure.message }),
|
|
9365
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mx-meet__empty-body", children: list.failure.remedy })
|
|
9366
|
+
] });
|
|
9269
9367
|
}
|
|
9270
|
-
if (
|
|
9271
|
-
|
|
9272
|
-
try {
|
|
9273
|
-
body = await response.json();
|
|
9274
|
-
} catch {
|
|
9275
|
-
body = null;
|
|
9276
|
-
}
|
|
9277
|
-
const said = readServerRefusal(body);
|
|
9278
|
-
return {
|
|
9279
|
-
messages: [],
|
|
9280
|
-
refusal: {
|
|
9281
|
-
message: said?.reason ?? `The chat could not be read (the server answered ${response.status}).`,
|
|
9282
|
-
remedy: said?.remedy || "Reload the page."
|
|
9283
|
-
}
|
|
9284
|
-
};
|
|
9368
|
+
if (list.loading) {
|
|
9369
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mx-meet__empty", role: "status", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mx-meet__empty-title", children: "Loading your meetings\u2026" }) });
|
|
9285
9370
|
}
|
|
9286
|
-
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9290
|
-
|
|
9291
|
-
).filter((message) => message !== null),
|
|
9292
|
-
refusal: null
|
|
9293
|
-
};
|
|
9294
|
-
}
|
|
9295
|
-
async function refusalOf(response, operation) {
|
|
9296
|
-
let body = null;
|
|
9297
|
-
try {
|
|
9298
|
-
body = await response.json();
|
|
9299
|
-
} catch {
|
|
9300
|
-
body = null;
|
|
9371
|
+
if (list.meetings.length === 0) {
|
|
9372
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mx-meet__empty", role: "status", children: [
|
|
9373
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mx-meet__empty-title", children: "No meetings yet" }),
|
|
9374
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mx-meet__empty-body", children: "Create one above. Its link works before, during and after the meeting \u2014 afterwards it opens the record." })
|
|
9375
|
+
] });
|
|
9301
9376
|
}
|
|
9302
|
-
const
|
|
9303
|
-
return
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9377
|
+
const origin = baseUrl ?? (typeof window === "undefined" ? "" : window.location.origin);
|
|
9378
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: "mx-meet-list", children: list.meetings.map((meeting) => {
|
|
9379
|
+
const ended = meeting.endedAt !== null;
|
|
9380
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { className: "mx-meet-list__row", children: [
|
|
9381
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mx-meet-list__main", children: [
|
|
9382
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "mx-meet-list__title", children: [
|
|
9383
|
+
meeting.title,
|
|
9384
|
+
ended ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "mx-meet__badge", children: "Ended" }) : null
|
|
9385
|
+
] }),
|
|
9386
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "mx-meet-list__when", children: meetingWhen(meeting) })
|
|
9387
|
+
] }),
|
|
9388
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { className: "mx-meet-list__action", href: meetingLink(origin, meeting.slug), children: ended ? "Open the record" : "Join" })
|
|
9389
|
+
] }, meeting.id);
|
|
9390
|
+
}) });
|
|
9308
9391
|
}
|
|
9309
|
-
|
|
9310
|
-
|
|
9392
|
+
|
|
9393
|
+
// src/core/invitations.ts
|
|
9394
|
+
var CALL_INVITE_KIND = "meet.call-invite";
|
|
9395
|
+
var CALL_INVITE_VERSION = 1;
|
|
9396
|
+
function callInviteAction(invite) {
|
|
9311
9397
|
return {
|
|
9312
|
-
|
|
9313
|
-
|
|
9314
|
-
|
|
9315
|
-
|
|
9316
|
-
|
|
9317
|
-
|
|
9398
|
+
kind: CALL_INVITE_KIND,
|
|
9399
|
+
version: CALL_INVITE_VERSION,
|
|
9400
|
+
payload: {
|
|
9401
|
+
invite_id: invite.id,
|
|
9402
|
+
room_name: invite.roomName,
|
|
9403
|
+
mode: invite.mode,
|
|
9404
|
+
caller_name: invite.callerName,
|
|
9405
|
+
expires_at: invite.expiresAt
|
|
9406
|
+
}
|
|
9318
9407
|
};
|
|
9319
9408
|
}
|
|
9320
|
-
|
|
9321
|
-
|
|
9322
|
-
|
|
9323
|
-
|
|
9324
|
-
|
|
9325
|
-
requireAuth: true,
|
|
9326
|
-
operation
|
|
9327
|
-
});
|
|
9328
|
-
if (!response.ok) throw await refusalOf(response, operation);
|
|
9329
|
-
const body = await response.json();
|
|
9330
|
-
const last = body["last_sent"];
|
|
9409
|
+
function callInviteText(invite) {
|
|
9410
|
+
return invite.mode === "video" ? `${invite.callerName} started a video call` : `${invite.callerName} started an audio call`;
|
|
9411
|
+
}
|
|
9412
|
+
function createCallInviteHandler(options) {
|
|
9413
|
+
const now = options.now ?? (() => Date.now());
|
|
9331
9414
|
return {
|
|
9332
|
-
|
|
9333
|
-
|
|
9334
|
-
|
|
9335
|
-
(
|
|
9336
|
-
|
|
9337
|
-
|
|
9338
|
-
|
|
9415
|
+
kind: CALL_INVITE_KIND,
|
|
9416
|
+
versions: [CALL_INVITE_VERSION],
|
|
9417
|
+
choices: (payload) => {
|
|
9418
|
+
if (Date.parse(payload.expires_at) < now()) return [];
|
|
9419
|
+
return [
|
|
9420
|
+
{ id: "join", label: payload.mode === "video" ? "Join video" : "Join call", tone: "primary" },
|
|
9421
|
+
{ id: "decline", label: "Decline", tone: "neutral" }
|
|
9422
|
+
];
|
|
9423
|
+
},
|
|
9424
|
+
summarize: (payload) => payload.mode === "video" ? `${payload.caller_name} started a video call` : `${payload.caller_name} started an audio call`,
|
|
9425
|
+
execute: async (payload, context) => {
|
|
9426
|
+
const settledAt = new Date(now()).toISOString();
|
|
9427
|
+
const inviteId = asCallId(payload.invite_id);
|
|
9428
|
+
const pending = await options.repository.pendingInvites(asUserId(String(context.actorId)));
|
|
9429
|
+
const live = pending.find((invite) => invite.id === inviteId) ?? null;
|
|
9430
|
+
if (live === null) {
|
|
9431
|
+
return {
|
|
9432
|
+
kind: CALL_INVITE_KIND,
|
|
9433
|
+
messageId: context.messageId,
|
|
9434
|
+
actorId: context.actorId,
|
|
9435
|
+
outcome: "unavailable",
|
|
9436
|
+
label: "This call has ended",
|
|
9437
|
+
settledAt,
|
|
9438
|
+
detail: "The invite is no longer ringing \u2014 it was answered elsewhere, cancelled, or it timed out. The chips are replaced by the outcome rather than left clickable."
|
|
9439
|
+
};
|
|
9440
|
+
}
|
|
9441
|
+
if (context.choice === "decline") {
|
|
9442
|
+
await options.calls.decline(inviteId);
|
|
9443
|
+
return {
|
|
9444
|
+
kind: CALL_INVITE_KIND,
|
|
9445
|
+
messageId: context.messageId,
|
|
9446
|
+
actorId: context.actorId,
|
|
9447
|
+
outcome: "declined",
|
|
9448
|
+
label: "Declined",
|
|
9449
|
+
settledAt
|
|
9450
|
+
};
|
|
9451
|
+
}
|
|
9452
|
+
const accepted = await options.calls.accept(inviteId, live.mode);
|
|
9453
|
+
await options.onJoin(accepted);
|
|
9454
|
+
return {
|
|
9455
|
+
kind: CALL_INVITE_KIND,
|
|
9456
|
+
messageId: context.messageId,
|
|
9457
|
+
actorId: context.actorId,
|
|
9458
|
+
outcome: "applied",
|
|
9459
|
+
label: "Joined",
|
|
9460
|
+
settledAt
|
|
9461
|
+
};
|
|
9462
|
+
}
|
|
9339
9463
|
};
|
|
9340
9464
|
}
|
|
9341
|
-
|
|
9342
|
-
|
|
9343
|
-
|
|
9344
|
-
|
|
9345
|
-
|
|
9346
|
-
|
|
9347
|
-
|
|
9348
|
-
body: {
|
|
9349
|
-
subject: input.subject,
|
|
9350
|
-
body: input.body,
|
|
9351
|
-
recipient_keys: [...input.recipientKeys],
|
|
9352
|
-
dry_run: input.dryRun === true
|
|
9353
|
-
}
|
|
9354
|
-
});
|
|
9355
|
-
if (!response.ok) throw await refusalOf(response, operation);
|
|
9356
|
-
const body = await response.json();
|
|
9465
|
+
var MEETING_INVITE_KIND = "meet.meeting-invite";
|
|
9466
|
+
var MEETING_INVITE_VERSION = 1;
|
|
9467
|
+
function meetingInviteAction(payload) {
|
|
9468
|
+
return { kind: MEETING_INVITE_KIND, version: MEETING_INVITE_VERSION, payload };
|
|
9469
|
+
}
|
|
9470
|
+
function createMeetingInviteHandler(options) {
|
|
9471
|
+
const now = options.now ?? (() => Date.now());
|
|
9357
9472
|
return {
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
|
|
9361
|
-
|
|
9362
|
-
|
|
9363
|
-
|
|
9473
|
+
kind: MEETING_INVITE_KIND,
|
|
9474
|
+
versions: [MEETING_INVITE_VERSION],
|
|
9475
|
+
// A DURABLE LINK NEVER EXPIRES (R3) — the chip stays useful after the
|
|
9476
|
+
// meeting too, because that is when people go looking for the notes.
|
|
9477
|
+
choices: () => [{ id: "open", label: "Open meeting", tone: "primary" }],
|
|
9478
|
+
summarize: (payload) => payload.scheduled_for === null ? payload.title : `${payload.title} \u2014 ${payload.scheduled_for}`,
|
|
9479
|
+
execute: async (payload, context) => {
|
|
9480
|
+
if (payload.slug.length === 0) {
|
|
9481
|
+
throw new MeetError(
|
|
9482
|
+
"invalid-response",
|
|
9483
|
+
"meet.meeting-invite: the payload carries no slug",
|
|
9484
|
+
"A meeting invitation without a durable slug cannot be opened. Fix the sender; never synthesize a link on the receiving side."
|
|
9485
|
+
);
|
|
9486
|
+
}
|
|
9487
|
+
await options.onOpen(payload);
|
|
9488
|
+
return {
|
|
9489
|
+
kind: MEETING_INVITE_KIND,
|
|
9490
|
+
messageId: context.messageId,
|
|
9491
|
+
actorId: context.actorId,
|
|
9492
|
+
outcome: "applied",
|
|
9493
|
+
label: "Opened",
|
|
9494
|
+
settledAt: new Date(now()).toISOString()
|
|
9495
|
+
};
|
|
9496
|
+
}
|
|
9364
9497
|
};
|
|
9365
9498
|
}
|
|
9366
9499
|
|
|
9367
9500
|
// src/core/management.ts
|
|
9368
|
-
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
|
|
9373
|
-
body = null;
|
|
9374
|
-
}
|
|
9375
|
-
const said = readServerRefusal(body);
|
|
9376
|
-
return new MeetError(
|
|
9377
|
-
response.status === 403 || response.status === 401 ? "forbidden" : response.status === 404 ? "not-found" : response.status === 409 ? "conflict" : "transport",
|
|
9378
|
-
`${operation}: ${said?.reason ?? `the server answered ${response.status}`}`,
|
|
9379
|
-
said?.remedy || "The meeting itself is saved \u2014 only the telling failed. Try again; the call is idempotent."
|
|
9501
|
+
function refusal(response, operation) {
|
|
9502
|
+
return refusalFromResponse(
|
|
9503
|
+
response,
|
|
9504
|
+
operation,
|
|
9505
|
+
"The meeting itself is saved \u2014 only the telling failed. Try again; the call is idempotent."
|
|
9380
9506
|
);
|
|
9381
9507
|
}
|
|
9382
9508
|
function count(body, key) {
|