@ai-matrx/meet 0.11.32 → 0.11.34
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 +35 -0
- package/dist/core.cjs +137 -48
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +75 -6
- package/dist/core.d.ts +75 -6
- package/dist/core.js +137 -48
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +137 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +137 -48
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +481 -79
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +6 -0
- package/dist/react.d.ts +6 -0
- package/dist/react.js +481 -79
- package/dist/react.js.map +1 -1
- package/dist/skins/meet.cjs +217 -33
- package/dist/skins/meet.cjs.map +1 -1
- package/dist/skins/meet.js +217 -33
- package/dist/skins/meet.js.map +1 -1
- package/dist/styles.css +19 -0
- package/package.json +2 -2
package/dist/core.js
CHANGED
|
@@ -13,12 +13,18 @@ var MeetError = class extends Error {
|
|
|
13
13
|
* renders `refused:<reason>` (or `ended`) from it — never from the HTTP status.
|
|
14
14
|
*/
|
|
15
15
|
reason;
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* A refusal that lifts by itself says when: whole seconds from the moment the server answered
|
|
18
|
+
* (a denial's cooldown, `reknock_cooldown_seconds`). Null for every refusal that does not.
|
|
19
|
+
*/
|
|
20
|
+
retryAfterSeconds;
|
|
21
|
+
constructor(code, message, remedy, cause, reason, retryAfterSeconds) {
|
|
17
22
|
super(message);
|
|
18
23
|
this.name = "MeetError";
|
|
19
24
|
this.code = code;
|
|
20
25
|
this.remedy = remedy;
|
|
21
26
|
this.reason = reason ?? null;
|
|
27
|
+
this.retryAfterSeconds = retryAfterSeconds ?? null;
|
|
22
28
|
if (cause !== void 0) this.cause = cause;
|
|
23
29
|
}
|
|
24
30
|
/** True when retrying after the host re-establishes a session is the fix. */
|
|
@@ -698,7 +704,8 @@ function parseRoomToken(body, roomName) {
|
|
|
698
704
|
const serverUrl = readString(payload, "server_url") ?? readString(payload, "serverUrl");
|
|
699
705
|
const identity = readString(payload, "identity");
|
|
700
706
|
const expiresAt = readString(payload, "expires_at") ?? readString(payload, "expiresAt");
|
|
701
|
-
|
|
707
|
+
const secondDeviceChoice = readString(payload, "second_device_choice");
|
|
708
|
+
if (token === null && secondDeviceChoice === null || serverUrl === null || identity === null) {
|
|
702
709
|
throw invalidResponse(
|
|
703
710
|
"meet.token",
|
|
704
711
|
"the response is missing token, server_url, or identity \u2014 joining with a partial token would fail inside LiveKit with an opaque error instead of here"
|
|
@@ -710,11 +717,15 @@ function parseRoomToken(body, roomName) {
|
|
|
710
717
|
"the response carries no expires_at. Without it the package cannot refresh before the token dies, and a long meeting silently loses its ability to reconnect"
|
|
711
718
|
);
|
|
712
719
|
}
|
|
720
|
+
const personKey = readString(payload, "person_key") ?? identity;
|
|
713
721
|
return {
|
|
714
|
-
token,
|
|
722
|
+
token: token ?? "",
|
|
715
723
|
serverUrl,
|
|
716
724
|
roomName,
|
|
717
|
-
identity,
|
|
725
|
+
identity: personKey,
|
|
726
|
+
connectionIdentity: readString(payload, "connection_identity") ?? personKey,
|
|
727
|
+
connectionKind: readString(payload, "connection_kind") === "companion" ? "companion" : "main",
|
|
728
|
+
secondDeviceChoice,
|
|
718
729
|
displayName: readString(payload, "display_name") ?? readString(payload, "displayName") ?? identity,
|
|
719
730
|
expiresAt,
|
|
720
731
|
canPublish: readBoolean(payload, "can_publish", true),
|
|
@@ -789,7 +800,9 @@ function createTokenClient(options) {
|
|
|
789
800
|
organization_id: input.identity.organizationId,
|
|
790
801
|
display_name: input.identity.displayName,
|
|
791
802
|
device_id: input.identity.deviceId,
|
|
792
|
-
guest
|
|
803
|
+
guest,
|
|
804
|
+
...input.tabId !== void 0 ? { tab_id: input.tabId } : {},
|
|
805
|
+
...input.secondDevice !== void 0 ? { second_device: input.secondDevice } : {}
|
|
793
806
|
}
|
|
794
807
|
});
|
|
795
808
|
} catch (error) {
|
|
@@ -806,7 +819,8 @@ function createTokenClient(options) {
|
|
|
806
819
|
said?.message ?? "You can't join this meeting.",
|
|
807
820
|
said?.remedy ?? "Ask the person who shared the link to let you in, then open the link again.",
|
|
808
821
|
void 0,
|
|
809
|
-
said?.reason ?? null
|
|
822
|
+
said?.reason ?? null,
|
|
823
|
+
said?.retryAfterSeconds ?? null
|
|
810
824
|
);
|
|
811
825
|
}
|
|
812
826
|
if (response.status === 404) {
|
|
@@ -864,6 +878,10 @@ function createTokenClient(options) {
|
|
|
864
878
|
if (!expired(entry)) return Promise.resolve(entry.token);
|
|
865
879
|
}
|
|
866
880
|
const pending = request(input, true).then((token) => {
|
|
881
|
+
if (token.secondDeviceChoice != null) {
|
|
882
|
+
cache.delete(input.roomName);
|
|
883
|
+
return token;
|
|
884
|
+
}
|
|
867
885
|
cache.set(input.roomName, { token, mintedAt: now(), inFlight: null });
|
|
868
886
|
remember(token);
|
|
869
887
|
return token;
|
|
@@ -898,6 +916,9 @@ function placeholder(roomName) {
|
|
|
898
916
|
serverUrl: "",
|
|
899
917
|
roomName,
|
|
900
918
|
identity: "",
|
|
919
|
+
connectionIdentity: "",
|
|
920
|
+
connectionKind: "main",
|
|
921
|
+
secondDeviceChoice: null,
|
|
901
922
|
displayName: "",
|
|
902
923
|
expiresAt: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
903
924
|
canPublish: false,
|
|
@@ -922,7 +943,9 @@ async function serverSentence(response) {
|
|
|
922
943
|
if (message === null) return null;
|
|
923
944
|
const remedy = typeof source.remedy === "string" && source.remedy.trim() !== "" ? source.remedy : void 0;
|
|
924
945
|
const reason = typeof source.reason === "string" && source.reason !== "" ? source.reason : null;
|
|
925
|
-
|
|
946
|
+
const retry = source.retry_after_seconds;
|
|
947
|
+
const retryAfterSeconds = typeof retry === "number" && Number.isFinite(retry) && retry > 0 ? Math.ceil(retry) : null;
|
|
948
|
+
return { message, remedy, reason, retryAfterSeconds };
|
|
926
949
|
} catch {
|
|
927
950
|
return null;
|
|
928
951
|
}
|
|
@@ -1398,7 +1421,10 @@ var JOINABLE_FROM = /* @__PURE__ */ new Set([
|
|
|
1398
1421
|
"superseded",
|
|
1399
1422
|
"inactive",
|
|
1400
1423
|
"denied",
|
|
1401
|
-
"knock_expired"
|
|
1424
|
+
"knock_expired",
|
|
1425
|
+
// A refused knock whose rule lets the person ask again (a cooldown that ran out): the machine
|
|
1426
|
+
// allows the press; the server's gate decides whether it knocks or is refused again.
|
|
1427
|
+
"refused:lobby_rejects"
|
|
1402
1428
|
]);
|
|
1403
1429
|
var NOT_ENDABLE = /* @__PURE__ */ new Set([
|
|
1404
1430
|
"ended",
|
|
@@ -1482,6 +1508,8 @@ function nextPhase(from, event) {
|
|
|
1482
1508
|
return WAITING_PHASES.has(from) ? "joining" : null;
|
|
1483
1509
|
case "connected":
|
|
1484
1510
|
return from === "joining" ? "in_call" : null;
|
|
1511
|
+
case "second_device":
|
|
1512
|
+
return from === "joining" ? "prejoin" : null;
|
|
1485
1513
|
case "join_failed":
|
|
1486
1514
|
return from === "joining" ? refusalPhase(event.reason) : null;
|
|
1487
1515
|
case "exit":
|
|
@@ -1499,7 +1527,7 @@ function nextPhase(from, event) {
|
|
|
1499
1527
|
case "call_outcome":
|
|
1500
1528
|
return RINGING.has(from) ? event.outcome : null;
|
|
1501
1529
|
case "reset":
|
|
1502
|
-
return LIVE_PHASES.has(from) ? null : "resolving";
|
|
1530
|
+
return LIVE_PHASES.has(from) && event.teardown !== true ? null : "resolving";
|
|
1503
1531
|
}
|
|
1504
1532
|
}
|
|
1505
1533
|
function resolveExit(input) {
|
|
@@ -1805,8 +1833,8 @@ function createCallCenter(options) {
|
|
|
1805
1833
|
"A late accept must not resurrect a settled call. Close the ringing UI; the caller has already moved on."
|
|
1806
1834
|
);
|
|
1807
1835
|
}
|
|
1808
|
-
if (options.store.snapshot().phase === "ringing_in") options.store.dispatch({ type: "call_answered" });
|
|
1809
1836
|
const settled = await repository.settleCallInvite(id, "connecting", null);
|
|
1837
|
+
if (options.store.snapshot().phase === "ringing_in") options.store.dispatch({ type: "call_answered" });
|
|
1810
1838
|
options.store.patch({ call: { invite: settled, direction: "incoming" } });
|
|
1811
1839
|
settleLocal(settled);
|
|
1812
1840
|
channel?.send(MEET_EVENTS.settled, settled);
|
|
@@ -3177,11 +3205,17 @@ async function loadMeetingActivities(api, meetingId, meetingPass = null) {
|
|
|
3177
3205
|
}
|
|
3178
3206
|
|
|
3179
3207
|
// src/core/names.ts
|
|
3208
|
+
var CONNECTION_SEPARATOR = "~";
|
|
3209
|
+
function personOf(identity) {
|
|
3210
|
+
const value = String(identity ?? "").trim();
|
|
3211
|
+
const cut = value.indexOf(CONNECTION_SEPARATOR);
|
|
3212
|
+
return cut === -1 ? value : value.slice(0, cut);
|
|
3213
|
+
}
|
|
3180
3214
|
function isGuestIdentity(identity) {
|
|
3181
|
-
return
|
|
3215
|
+
return personOf(identity).startsWith("guest:");
|
|
3182
3216
|
}
|
|
3183
3217
|
function isAgentIdentity(identity) {
|
|
3184
|
-
return
|
|
3218
|
+
return personOf(identity).startsWith("agent:");
|
|
3185
3219
|
}
|
|
3186
3220
|
var NOTE_TAKER_PRODUCT_NAME = "Matrx note-taker";
|
|
3187
3221
|
var AGENT_PRODUCT_NAME = "Matrx agent";
|
|
@@ -3395,6 +3429,7 @@ var EMPTY = {
|
|
|
3395
3429
|
waiting: null,
|
|
3396
3430
|
meeting: null,
|
|
3397
3431
|
localIdentity: null,
|
|
3432
|
+
secondDevice: null,
|
|
3398
3433
|
grants: NO_GRANTS,
|
|
3399
3434
|
participants: [],
|
|
3400
3435
|
activeSpeakers: [],
|
|
@@ -3645,7 +3680,8 @@ function createMeetStore(initial = {}) {
|
|
|
3645
3680
|
commit({ ...state, media: { ...state.media, [kind]: next } });
|
|
3646
3681
|
},
|
|
3647
3682
|
reset() {
|
|
3648
|
-
|
|
3683
|
+
const phase = nextPhase(state.phase, { type: "reset", teardown: true }) ?? EMPTY.phase;
|
|
3684
|
+
commit({ ...EMPTY, effects: state.effects, phase, reason: reasonOf(phase), phaseNotice: null });
|
|
3649
3685
|
}
|
|
3650
3686
|
};
|
|
3651
3687
|
}
|
|
@@ -4724,6 +4760,28 @@ function lobbyEntryFrom(attendee, now = Date.now()) {
|
|
|
4724
4760
|
decidedBy: null
|
|
4725
4761
|
};
|
|
4726
4762
|
}
|
|
4763
|
+
function deniedEntryFrom(attendee) {
|
|
4764
|
+
if (attendee.admissionState !== "denied") return null;
|
|
4765
|
+
return {
|
|
4766
|
+
identity: attendee.identity,
|
|
4767
|
+
displayName: attendee.displayName,
|
|
4768
|
+
avatarUrl: attendee.avatarUrl,
|
|
4769
|
+
userId: attendee.userId,
|
|
4770
|
+
state: "denied",
|
|
4771
|
+
knockedAt: attendee.knockedAt ?? attendee.joinedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
4772
|
+
knockExpiresAt: null,
|
|
4773
|
+
decidedAt: null,
|
|
4774
|
+
decidedBy: null
|
|
4775
|
+
};
|
|
4776
|
+
}
|
|
4777
|
+
function applyDoorRow(store, attendee) {
|
|
4778
|
+
const entry = lobbyEntryFrom(attendee) ?? deniedEntryFrom(attendee);
|
|
4779
|
+
if (entry !== null) {
|
|
4780
|
+
store.upsertLobby(entry);
|
|
4781
|
+
return;
|
|
4782
|
+
}
|
|
4783
|
+
store.setAdmission(attendee.identity, decidedState(attendee.admissionState), null);
|
|
4784
|
+
}
|
|
4727
4785
|
function decidedState(state) {
|
|
4728
4786
|
return WAITING_ADMISSION_STATES.includes(state) ? "expired" : state;
|
|
4729
4787
|
}
|
|
@@ -4858,6 +4916,7 @@ function createMeetingSession(options) {
|
|
|
4858
4916
|
admission,
|
|
4859
4917
|
admittersPresent: read.admitters_present ?? null,
|
|
4860
4918
|
reknockAllowed: read.reknock_allowed ?? true,
|
|
4919
|
+
reknockAt: typeof read.reknock_in_seconds === "number" && read.reknock_in_seconds > 0 ? Date.now() + read.reknock_in_seconds * 1e3 : null,
|
|
4861
4920
|
knockExpiresAt: read.knock_expires_at ?? null,
|
|
4862
4921
|
pollSeconds: read.poll_seconds ?? snapshot.waiting?.pollSeconds ?? 3,
|
|
4863
4922
|
liveVersion: read.live_version ?? 0
|
|
@@ -4940,11 +4999,7 @@ function createMeetingSession(options) {
|
|
|
4940
4999
|
try {
|
|
4941
5000
|
const attendees = await repository.attendees(meeting.id);
|
|
4942
5001
|
store.learn(attendees);
|
|
4943
|
-
for (const attendee of attendees)
|
|
4944
|
-
const entry = lobbyEntryFrom(attendee);
|
|
4945
|
-
if (entry !== null) store.upsertLobby(entry);
|
|
4946
|
-
else store.setAdmission(attendee.identity, decidedState(attendee.admissionState), null);
|
|
4947
|
-
}
|
|
5002
|
+
for (const attendee of attendees) applyDoorRow(store, attendee);
|
|
4948
5003
|
} catch {
|
|
4949
5004
|
}
|
|
4950
5005
|
}
|
|
@@ -5026,12 +5081,7 @@ function createMeetingSession(options) {
|
|
|
5026
5081
|
if (row === null) return;
|
|
5027
5082
|
const attendee = repository.projectAttendee(row);
|
|
5028
5083
|
store.learn([attendee]);
|
|
5029
|
-
|
|
5030
|
-
if (entry !== null) {
|
|
5031
|
-
store.upsertLobby(entry);
|
|
5032
|
-
return;
|
|
5033
|
-
}
|
|
5034
|
-
store.setAdmission(attendee.identity, decidedState(attendee.admissionState), null);
|
|
5084
|
+
applyDoorRow(store, attendee);
|
|
5035
5085
|
}
|
|
5036
5086
|
},
|
|
5037
5087
|
{
|
|
@@ -5078,14 +5128,7 @@ function createMeetingSession(options) {
|
|
|
5078
5128
|
store.setRecording(latest.state, latest.startedBy, "record", latest.id);
|
|
5079
5129
|
}
|
|
5080
5130
|
store.learn(attendees);
|
|
5081
|
-
for (const attendee of attendees)
|
|
5082
|
-
const entry = lobbyEntryFrom(attendee);
|
|
5083
|
-
if (entry !== null) {
|
|
5084
|
-
store.upsertLobby(entry);
|
|
5085
|
-
} else {
|
|
5086
|
-
store.setAdmission(attendee.identity, decidedState(attendee.admissionState), null);
|
|
5087
|
-
}
|
|
5088
|
-
}
|
|
5131
|
+
for (const attendee of attendees) applyDoorRow(store, attendee);
|
|
5089
5132
|
}
|
|
5090
5133
|
});
|
|
5091
5134
|
meetingChannel.requestBackfill("manual");
|
|
@@ -5137,9 +5180,9 @@ function createMeetingSession(options) {
|
|
|
5137
5180
|
},
|
|
5138
5181
|
stopWaiting,
|
|
5139
5182
|
readState: readState2,
|
|
5140
|
-
async readExit(connection) {
|
|
5183
|
+
async readExit(connection, held) {
|
|
5141
5184
|
const meeting = store.snapshot().meeting;
|
|
5142
|
-
const pass = options.resolvePass?.() ?? null;
|
|
5185
|
+
const pass = held ?? options.resolvePass?.() ?? null;
|
|
5143
5186
|
if (meeting === null || pass === null) return void 0;
|
|
5144
5187
|
try {
|
|
5145
5188
|
const response = await options.api.request({
|
|
@@ -6129,6 +6172,7 @@ function SCREEN_SHARE_BLOCKED_REMEDY_FOR(remedy) {
|
|
|
6129
6172
|
}
|
|
6130
6173
|
var PARTICIPANT_ROLE_ATTRIBUTE = "matrx.participant.role";
|
|
6131
6174
|
var PARTICIPANT_CAN_RECORD_ATTRIBUTE = "matrx.participant.can_record";
|
|
6175
|
+
var CONNECTION_KIND_ATTRIBUTE = "matrx.participant.connection_kind";
|
|
6132
6176
|
var PARTICIPANT_STANDING_ATTRIBUTE = "matrx.participant.standing";
|
|
6133
6177
|
var KNOWN_STANDINGS = ["member", "invited", "outsider", "guest"];
|
|
6134
6178
|
function parseStanding(value) {
|
|
@@ -6152,7 +6196,8 @@ function projectParticipant(driver, joinedAt) {
|
|
|
6152
6196
|
}
|
|
6153
6197
|
const userId = typeof metadata.user_id === "string" ? asUserId(metadata.user_id) : null;
|
|
6154
6198
|
return {
|
|
6155
|
-
|
|
6199
|
+
// S7: a tile is a PERSON; LiveKit names the tab's connection (`<person>~<tab>`).
|
|
6200
|
+
identity: personOf(driver.identity),
|
|
6156
6201
|
userId,
|
|
6157
6202
|
// 🚨 A RAW LIVEKIT IDENTITY IS NEVER A NAME (MRI-A18). Through 0.4.12 this
|
|
6158
6203
|
// line read `driver.name.length > 0 ? driver.name : driver.identity`, and
|
|
@@ -6199,6 +6244,11 @@ function createRoomEngine(options) {
|
|
|
6199
6244
|
let ghosts = /* @__PURE__ */ new Map();
|
|
6200
6245
|
let ghostTimer = null;
|
|
6201
6246
|
let liveRoster = [];
|
|
6247
|
+
let personConnections = /* @__PURE__ */ new Map();
|
|
6248
|
+
let mainConnection = /* @__PURE__ */ new Map();
|
|
6249
|
+
function connectionsOf(who) {
|
|
6250
|
+
return personConnections.get(personOf(who)) ?? [who];
|
|
6251
|
+
}
|
|
6202
6252
|
const departures = /* @__PURE__ */ new Map();
|
|
6203
6253
|
function requestAsNow() {
|
|
6204
6254
|
if (lastRequest === null) return null;
|
|
@@ -6263,7 +6313,12 @@ function createRoomEngine(options) {
|
|
|
6263
6313
|
function failJoin(error, operation) {
|
|
6264
6314
|
const normalized = normalizeMeetError(error, operation);
|
|
6265
6315
|
store.patch({
|
|
6266
|
-
failure: {
|
|
6316
|
+
failure: {
|
|
6317
|
+
message: normalized.message,
|
|
6318
|
+
remedy: normalized.remedy,
|
|
6319
|
+
reason: normalized.reason,
|
|
6320
|
+
retryAt: normalized.retryAfterSeconds === null ? null : now() + normalized.retryAfterSeconds * 1e3
|
|
6321
|
+
}
|
|
6267
6322
|
});
|
|
6268
6323
|
store.dispatch({ type: "join_failed", reason: normalized.reason ?? null });
|
|
6269
6324
|
report(
|
|
@@ -6335,10 +6390,10 @@ function createRoomEngine(options) {
|
|
|
6335
6390
|
if (store.snapshot().spotlight !== spotlight) store.patch({ spotlight });
|
|
6336
6391
|
},
|
|
6337
6392
|
activeSpeakers(identities) {
|
|
6338
|
-
store.setSpeaking(identities.map(
|
|
6393
|
+
store.setSpeaking([...new Set(identities.map((who) => personOf(who)))]);
|
|
6339
6394
|
},
|
|
6340
6395
|
quality(who, value) {
|
|
6341
|
-
store.setQuality(
|
|
6396
|
+
store.setQuality(personOf(who), value);
|
|
6342
6397
|
},
|
|
6343
6398
|
connectionState(state) {
|
|
6344
6399
|
supervisor.driverState(state);
|
|
@@ -6358,7 +6413,7 @@ function createRoomEngine(options) {
|
|
|
6358
6413
|
);
|
|
6359
6414
|
return;
|
|
6360
6415
|
}
|
|
6361
|
-
const speakerIdentity =
|
|
6416
|
+
const speakerIdentity = personOf(event.speakerIdentity);
|
|
6362
6417
|
const speaker = snapshot.participants.find(
|
|
6363
6418
|
(participant) => participant.identity === speakerIdentity
|
|
6364
6419
|
);
|
|
@@ -6432,7 +6487,7 @@ function createRoomEngine(options) {
|
|
|
6432
6487
|
);
|
|
6433
6488
|
return;
|
|
6434
6489
|
}
|
|
6435
|
-
const sender =
|
|
6490
|
+
const sender = personOf(from ?? "");
|
|
6436
6491
|
switch (topic) {
|
|
6437
6492
|
case DATA_TOPICS.hand:
|
|
6438
6493
|
store.setHand(
|
|
@@ -6474,7 +6529,8 @@ function createRoomEngine(options) {
|
|
|
6474
6529
|
}
|
|
6475
6530
|
};
|
|
6476
6531
|
async function resolveExitAndApply(hint) {
|
|
6477
|
-
const connection = current?.identity ?? store.snapshot().localIdentity ?? null;
|
|
6532
|
+
const connection = current?.connectionIdentity ?? current?.identity ?? store.snapshot().localIdentity ?? null;
|
|
6533
|
+
const heldPass = current?.meetingPass ?? null;
|
|
6478
6534
|
lastRequest = requestAsNow();
|
|
6479
6535
|
await dropRoom();
|
|
6480
6536
|
let server;
|
|
@@ -6482,7 +6538,7 @@ function createRoomEngine(options) {
|
|
|
6482
6538
|
server = void 0;
|
|
6483
6539
|
} else {
|
|
6484
6540
|
try {
|
|
6485
|
-
server = await options.readExit(connection);
|
|
6541
|
+
server = await options.readExit(connection, heldPass);
|
|
6486
6542
|
} catch {
|
|
6487
6543
|
server = null;
|
|
6488
6544
|
}
|
|
@@ -6512,14 +6568,29 @@ function createRoomEngine(options) {
|
|
|
6512
6568
|
}
|
|
6513
6569
|
async function connect(request) {
|
|
6514
6570
|
store.patch({ failure: null, waiting: null, roomName: request.roomName, share: NO_SHARE, connection: "stable" });
|
|
6571
|
+
const tabId = options.tabClaim !== void 0 ? await options.tabClaim.tabId : null;
|
|
6515
6572
|
const token = await tokens.get({
|
|
6516
6573
|
roomName: request.roomName,
|
|
6517
6574
|
identity,
|
|
6518
6575
|
...request.meetingId !== void 0 ? { meetingId: request.meetingId } : {},
|
|
6519
6576
|
...request.slug !== void 0 ? { slug: request.slug } : {},
|
|
6520
6577
|
...request.breakoutRoomId != null ? { breakoutRoomId: request.breakoutRoomId } : {},
|
|
6521
|
-
...request.observe === true ? { observe: true } : {}
|
|
6578
|
+
...request.observe === true ? { observe: true } : {},
|
|
6579
|
+
...tabId !== null ? { tabId } : {},
|
|
6580
|
+
...request.secondDevice !== void 0 ? { secondDevice: request.secondDevice } : {}
|
|
6522
6581
|
});
|
|
6582
|
+
if (token.secondDeviceChoice != null) {
|
|
6583
|
+
store.patch({ secondDevice: { rule: token.secondDeviceChoice }, localIdentity: token.identity });
|
|
6584
|
+
store.dispatch({ type: "second_device" });
|
|
6585
|
+
report("info", `meet: already in this meeting elsewhere \u2014 offering the choice (${token.secondDeviceChoice})`);
|
|
6586
|
+
return;
|
|
6587
|
+
}
|
|
6588
|
+
if (store.snapshot().secondDevice !== null) store.patch({ secondDevice: null });
|
|
6589
|
+
if (request.secondDevice === "switch_here" && lastRequest !== null) {
|
|
6590
|
+
const { secondDevice: _answered, ...rest } = lastRequest;
|
|
6591
|
+
lastRequest = rest;
|
|
6592
|
+
}
|
|
6593
|
+
options.tabClaim?.inRoom(String(request.roomName), String(token.identity));
|
|
6523
6594
|
current = token;
|
|
6524
6595
|
lastServerUrl = token.serverUrl;
|
|
6525
6596
|
connectionPolicy = token.connectionPolicy ?? DEFAULT_CONNECTION_POLICY;
|
|
@@ -6584,7 +6655,7 @@ function createRoomEngine(options) {
|
|
|
6584
6655
|
if (request.mode === "video") {
|
|
6585
6656
|
await enableTrack(created, "camera", true);
|
|
6586
6657
|
}
|
|
6587
|
-
if (request.microphone !== false) {
|
|
6658
|
+
if (request.microphone !== false && current?.connectionKind !== "companion") {
|
|
6588
6659
|
await enableTrack(created, "microphone", true);
|
|
6589
6660
|
}
|
|
6590
6661
|
media.onConnected();
|
|
@@ -6606,7 +6677,8 @@ function createRoomEngine(options) {
|
|
|
6606
6677
|
}
|
|
6607
6678
|
async function publish(topic, body, to) {
|
|
6608
6679
|
if (driver === null) return;
|
|
6609
|
-
|
|
6680
|
+
const addresses = to === void 0 ? void 0 : to.flatMap((who) => connectionsOf(who));
|
|
6681
|
+
await driver.publishData(topic, JSON.stringify(body), addresses);
|
|
6610
6682
|
}
|
|
6611
6683
|
async function applyEffects(target, effects) {
|
|
6612
6684
|
try {
|
|
@@ -6644,8 +6716,19 @@ function createRoomEngine(options) {
|
|
|
6644
6716
|
liveRoster = list;
|
|
6645
6717
|
const merged = mergeGhosts(list, ghosts, at);
|
|
6646
6718
|
ghosts = merged.kept;
|
|
6719
|
+
const people = /* @__PURE__ */ new Map();
|
|
6720
|
+
const connections = /* @__PURE__ */ new Map();
|
|
6721
|
+
for (const entry of merged.roster) {
|
|
6722
|
+
const person = personOf(entry.identity);
|
|
6723
|
+
connections.set(person, [...connections.get(person) ?? [], entry.identity]);
|
|
6724
|
+
const rank = (entry.isLocal ? 8 : 0) + (entry.reconnecting === true ? 0 : 4) + (entry.attributes[CONNECTION_KIND_ATTRIBUTE] === "companion" ? 0 : 2) + (entry.cameraEnabled || entry.micEnabled ? 1 : 0);
|
|
6725
|
+
const held = people.get(person);
|
|
6726
|
+
if (held === void 0 || rank > held.rank) people.set(person, { entry, rank });
|
|
6727
|
+
}
|
|
6728
|
+
personConnections = connections;
|
|
6729
|
+
mainConnection = new Map([...people].map(([person, { entry }]) => [person, entry.identity]));
|
|
6647
6730
|
store.setParticipants(
|
|
6648
|
-
|
|
6731
|
+
[...people.values()].map(({ entry }) => {
|
|
6649
6732
|
const projected = projectParticipant(entry, joinedAt);
|
|
6650
6733
|
return entry.reconnecting === true ? { ...projected, reconnecting: true, quality: "lost" } : projected;
|
|
6651
6734
|
})
|
|
@@ -6822,7 +6905,13 @@ function createRoomEngine(options) {
|
|
|
6822
6905
|
},
|
|
6823
6906
|
async setScreenShareEnabled(enabled) {
|
|
6824
6907
|
if (driver === null) return;
|
|
6825
|
-
|
|
6908
|
+
let unsupported = false;
|
|
6909
|
+
try {
|
|
6910
|
+
unsupported = enabled && driver.supportsScreenShare?.() === false;
|
|
6911
|
+
} catch {
|
|
6912
|
+
unsupported = false;
|
|
6913
|
+
}
|
|
6914
|
+
if (unsupported) {
|
|
6826
6915
|
store.patch({ share: { state: "refused", reason: "unsupported", remedy: null, at: now() } });
|
|
6827
6916
|
report("warn", "meet: this browser cannot share a screen", "Share from a desktop browser (Chrome, Edge, Firefox or Safari).");
|
|
6828
6917
|
return;
|
|
@@ -6921,7 +7010,7 @@ function createRoomEngine(options) {
|
|
|
6921
7010
|
},
|
|
6922
7011
|
attach(who, kind, element) {
|
|
6923
7012
|
if (driver === null) return () => void 0;
|
|
6924
|
-
return driver.attach(who, kind, element);
|
|
7013
|
+
return driver.attach(mainConnection.get(personOf(who)) ?? who, kind, element);
|
|
6925
7014
|
},
|
|
6926
7015
|
token: () => current,
|
|
6927
7016
|
async dispose() {
|