@ai-matrx/meet 0.11.36 → 0.11.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/core.cjs +75 -86
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +60 -22
- package/dist/core.d.ts +60 -22
- package/dist/core.js +75 -86
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +75 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +75 -86
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +181 -106
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +17 -3
- package/dist/react.d.ts +17 -3
- package/dist/react.js +181 -106
- package/dist/react.js.map +1 -1
- package/dist/skins/meet.cjs +118 -20
- package/dist/skins/meet.cjs.map +1 -1
- package/dist/skins/meet.js +118 -20
- package/dist/skins/meet.js.map +1 -1
- package/dist/styles.css +7 -0
- package/package.json +5 -5
package/dist/react.cjs
CHANGED
|
@@ -40,6 +40,7 @@ __export(react_exports, {
|
|
|
40
40
|
DATA_TOPICS: () => DATA_TOPICS,
|
|
41
41
|
DEFAULT_CONNECTION_POLICY: () => DEFAULT_CONNECTION_POLICY,
|
|
42
42
|
DEFAULT_EFFECTS: () => DEFAULT_EFFECTS,
|
|
43
|
+
DEFAULT_LEAVE_POLICY: () => DEFAULT_LEAVE_POLICY,
|
|
43
44
|
DEFAULT_PAGE_SIZE: () => DEFAULT_PAGE_SIZE,
|
|
44
45
|
EMPTY_COLLAB: () => EMPTY_COLLAB,
|
|
45
46
|
END_MEETING_NOT_SERVED: () => END_MEETING_NOT_SERVED,
|
|
@@ -83,6 +84,7 @@ __export(react_exports, {
|
|
|
83
84
|
NO_SHARE: () => NO_SHARE,
|
|
84
85
|
ORGANIZATION_HEADER: () => ORGANIZATION_HEADER,
|
|
85
86
|
PARTICIPANT_CAN_RECORD_ATTRIBUTE: () => PARTICIPANT_CAN_RECORD_ATTRIBUTE,
|
|
87
|
+
PARTICIPANT_HAND_ATTRIBUTE: () => PARTICIPANT_HAND_ATTRIBUTE,
|
|
86
88
|
PARTICIPANT_ROLE_ATTRIBUTE: () => PARTICIPANT_ROLE_ATTRIBUTE,
|
|
87
89
|
PARTICIPANT_STANDING_ATTRIBUTE: () => PARTICIPANT_STANDING_ATTRIBUTE,
|
|
88
90
|
REACTION_TTL_MS: () => REACTION_TTL_MS,
|
|
@@ -196,6 +198,8 @@ __export(react_exports, {
|
|
|
196
198
|
isWaitingPhase: () => isWaitingPhase,
|
|
197
199
|
learnName: () => learnName,
|
|
198
200
|
learnNames: () => learnNames,
|
|
201
|
+
leaveChoices: () => leaveChoices,
|
|
202
|
+
leavePolicyFrom: () => leavePolicyFrom,
|
|
199
203
|
listenOnlyNotice: () => listenOnlyNotice,
|
|
200
204
|
loadFollowUpDraft: () => loadFollowUpDraft,
|
|
201
205
|
loadGuestMeetingRecord: () => loadGuestMeetingRecord,
|
|
@@ -297,6 +301,7 @@ __export(react_exports, {
|
|
|
297
301
|
useHandQueue: () => useHandQueue,
|
|
298
302
|
useHostControls: () => useHostControls,
|
|
299
303
|
useIsHost: () => useIsHost,
|
|
304
|
+
useLeave: () => useLeave,
|
|
300
305
|
useListenOnlyNotice: () => useListenOnlyNotice,
|
|
301
306
|
useLobby: () => useLobby,
|
|
302
307
|
useLocalMedia: () => useLocalMedia,
|
|
@@ -1026,6 +1031,30 @@ function invalidResponse(operation, detail) {
|
|
|
1026
1031
|
);
|
|
1027
1032
|
}
|
|
1028
1033
|
|
|
1034
|
+
// src/core/leave.ts
|
|
1035
|
+
var DEFAULT_LEAVE_POLICY = { hostLeavePrompt: "leave_or_end", endConfirm: false };
|
|
1036
|
+
var PROMPTS = ["leave_or_end", "must_assign_or_end", "leave_only"];
|
|
1037
|
+
function leavePolicyFrom(raw) {
|
|
1038
|
+
if (typeof raw !== "object" || raw === null) return DEFAULT_LEAVE_POLICY;
|
|
1039
|
+
const value = raw;
|
|
1040
|
+
const prompt = value["host_leave_prompt"];
|
|
1041
|
+
const confirm = value["end_confirm"];
|
|
1042
|
+
return {
|
|
1043
|
+
hostLeavePrompt: PROMPTS.includes(prompt) ? prompt : DEFAULT_LEAVE_POLICY.hostLeavePrompt,
|
|
1044
|
+
endConfirm: typeof confirm === "boolean" ? confirm : DEFAULT_LEAVE_POLICY.endConfirm
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
function leaveChoices(args) {
|
|
1048
|
+
if (args.role !== "host") return ["leave"];
|
|
1049
|
+
switch (args.policy.hostLeavePrompt) {
|
|
1050
|
+
case "must_assign_or_end":
|
|
1051
|
+
return args.othersPresent ? ["assign_and_leave", "end_for_all"] : ["leave", "end_for_all"];
|
|
1052
|
+
case "leave_only":
|
|
1053
|
+
case "leave_or_end":
|
|
1054
|
+
return ["leave", "end_for_all"];
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1029
1058
|
// src/core/tokens.ts
|
|
1030
1059
|
function createWebRoomTokenStorage(onDiagnostic) {
|
|
1031
1060
|
const store = globalThis.localStorage;
|
|
@@ -1217,7 +1246,8 @@ function parseRoomToken(body, roomName) {
|
|
|
1217
1246
|
pollSeconds: typeof payload["poll_seconds"] === "number" ? payload["poll_seconds"] : void 0,
|
|
1218
1247
|
breakoutRoomId: readString(payload, "breakout_room_id") ?? null,
|
|
1219
1248
|
observersVisibleTo: readString(payload, "observers_visible_to") === "hosts" ? "hosts" : "everyone",
|
|
1220
|
-
connectionPolicy: connectionPolicyFrom(payload["connection_policy"])
|
|
1249
|
+
connectionPolicy: connectionPolicyFrom(payload["connection_policy"]),
|
|
1250
|
+
leavePolicy: leavePolicyFrom(payload["leave_policy"])
|
|
1221
1251
|
};
|
|
1222
1252
|
}
|
|
1223
1253
|
function createTokenClient(options) {
|
|
@@ -4117,6 +4147,10 @@ var EMPTY = {
|
|
|
4117
4147
|
chatHistoryError: null,
|
|
4118
4148
|
reactions: [],
|
|
4119
4149
|
spotlight: null,
|
|
4150
|
+
actingHost: null,
|
|
4151
|
+
presenter: null,
|
|
4152
|
+
waitingCount: 0,
|
|
4153
|
+
leavePolicy: DEFAULT_LEAVE_POLICY,
|
|
4120
4154
|
moderationNotice: null,
|
|
4121
4155
|
actionNotice: null,
|
|
4122
4156
|
privateChatRequest: null,
|
|
@@ -4178,8 +4212,6 @@ function createMeetStore(initial = {}) {
|
|
|
4178
4212
|
},
|
|
4179
4213
|
setParticipants(participants) {
|
|
4180
4214
|
const names = learnNames(state.names, participants);
|
|
4181
|
-
const hands = new Map(state.participants.map((p) => [p.identity, p.handRaised]));
|
|
4182
|
-
const handTimes = new Map(state.participants.map((p) => [p.identity, p.handRaisedAt ?? null]));
|
|
4183
4215
|
const quality = new Map(state.participants.map((p) => [p.identity, p.quality]));
|
|
4184
4216
|
commit({
|
|
4185
4217
|
...state,
|
|
@@ -4192,8 +4224,6 @@ function createMeetStore(initial = {}) {
|
|
|
4192
4224
|
// identity could reach a screen, and it is the place that asks the
|
|
4193
4225
|
// name book. `roster-names.test.ts` fails if a token ever gets past it.
|
|
4194
4226
|
displayName: displayNameFor(names, participant.identity, participant.displayName),
|
|
4195
|
-
handRaised: hands.get(participant.identity) ?? participant.handRaised,
|
|
4196
|
-
handRaisedAt: handTimes.get(participant.identity) ?? participant.handRaisedAt ?? null,
|
|
4197
4227
|
quality: participant.quality === "unknown" ? quality.get(participant.identity) ?? "unknown" : participant.quality
|
|
4198
4228
|
}))
|
|
4199
4229
|
});
|
|
@@ -4216,20 +4246,6 @@ function createMeetStore(initial = {}) {
|
|
|
4216
4246
|
)
|
|
4217
4247
|
});
|
|
4218
4248
|
},
|
|
4219
|
-
setHand(identity, raised, at) {
|
|
4220
|
-
commit({
|
|
4221
|
-
...state,
|
|
4222
|
-
participants: state.participants.map(
|
|
4223
|
-
(participant) => participant.identity === identity ? {
|
|
4224
|
-
...participant,
|
|
4225
|
-
handRaised: raised,
|
|
4226
|
-
// A hand that is ALREADY up keeps its place in the queue when
|
|
4227
|
-
// it is re-announced (to a late joiner): the first time wins.
|
|
4228
|
-
handRaisedAt: raised ? participant.handRaised && participant.handRaisedAt != null ? participant.handRaisedAt : at ?? Date.now() : null
|
|
4229
|
-
} : participant
|
|
4230
|
-
)
|
|
4231
|
-
});
|
|
4232
|
-
},
|
|
4233
4249
|
addChat(message) {
|
|
4234
4250
|
if (state.chat.some((existing) => existing.id === message.id)) return;
|
|
4235
4251
|
const chat = [...state.chat, message];
|
|
@@ -4589,7 +4605,7 @@ function createMeetingSession(options) {
|
|
|
4589
4605
|
})();
|
|
4590
4606
|
return reading;
|
|
4591
4607
|
}
|
|
4592
|
-
async function postLeave(intent) {
|
|
4608
|
+
async function postLeave(intent, extra = {}) {
|
|
4593
4609
|
const meeting = requireMeeting(`meet.${intent}`);
|
|
4594
4610
|
const pass = options.resolvePass?.() ?? null;
|
|
4595
4611
|
const response = await options.api.request({
|
|
@@ -4597,7 +4613,7 @@ function createMeetingSession(options) {
|
|
|
4597
4613
|
method: "POST",
|
|
4598
4614
|
requireAuth: false,
|
|
4599
4615
|
operation: `meet.${intent}`,
|
|
4600
|
-
body: { meeting_id: meeting.id, intent },
|
|
4616
|
+
body: { meeting_id: meeting.id, intent, ...extra },
|
|
4601
4617
|
...pass !== null ? { headers: { [MEETING_PASS_HEADER]: pass } } : {}
|
|
4602
4618
|
});
|
|
4603
4619
|
if (!response.ok) {
|
|
@@ -4611,7 +4627,7 @@ function createMeetingSession(options) {
|
|
|
4611
4627
|
throw new MeetError(
|
|
4612
4628
|
"transport",
|
|
4613
4629
|
refusal2?.reason ?? `meet.${intent}: the server answered ${response.status}`,
|
|
4614
|
-
refusal2?.remedy ?? "You are still in the waiting room. Try again."
|
|
4630
|
+
refusal2?.remedy ?? (intent === "withdraw" ? "You are still in the waiting room. Try again." : "Nothing was changed. Try again.")
|
|
4615
4631
|
);
|
|
4616
4632
|
}
|
|
4617
4633
|
}
|
|
@@ -4835,6 +4851,10 @@ function createMeetingSession(options) {
|
|
|
4835
4851
|
store.dispatch({ type: "admission", admission: "withdrawn" });
|
|
4836
4852
|
hint();
|
|
4837
4853
|
},
|
|
4854
|
+
async hostLeave(intent) {
|
|
4855
|
+
if (intent === "end_for_all") await postLeave("end_for_all");
|
|
4856
|
+
else await postLeave("assign_and_leave", { assign_to: intent.assignTo });
|
|
4857
|
+
},
|
|
4838
4858
|
async askAgain() {
|
|
4839
4859
|
await options.rejoin?.();
|
|
4840
4860
|
},
|
|
@@ -5295,18 +5315,6 @@ var ROOM_EVENTS = {
|
|
|
5295
5315
|
wrapUp: "matrx.meet.wrap_up",
|
|
5296
5316
|
/** The meeting ended for everyone. Payload `{ meeting_id, ended_at, trigger }`. */
|
|
5297
5317
|
ended: "matrx.meet.ended",
|
|
5298
|
-
/**
|
|
5299
|
-
* A `meet_recordings` row changed state. Payload
|
|
5300
|
-
* `{ meeting_id, recording: { id, state, started_by } }`.
|
|
5301
|
-
*
|
|
5302
|
-
* 🚨 THIS IS THE ONLY WAY A GUEST LEARNS A RECORDING IS RUNNING. PreJoin
|
|
5303
|
-
* promises every joiner an indicator, and `anon` holds no SELECT grant on
|
|
5304
|
-
* `meet_recordings` (MRI-A10 settled that widening it is forbidden), so
|
|
5305
|
-
* without this packet the promise was a sentence with nothing behind it: on
|
|
5306
|
-
* production 2026-09-09 the guest lane showed no indicator at all while the
|
|
5307
|
-
* host recorded (MRI-C8).
|
|
5308
|
-
*/
|
|
5309
|
-
recording: "matrx.meet.recording",
|
|
5310
5318
|
/**
|
|
5311
5319
|
* A chat message to everyone was SAVED (Meet wave 2). Payload
|
|
5312
5320
|
* `{ message: { id, meeting_id, sender_identity, sender_name, body, created_at } }`.
|
|
@@ -5359,8 +5367,6 @@ function applyRoomEvent(args) {
|
|
|
5359
5367
|
return applyWrapUp(store, payload, now);
|
|
5360
5368
|
case ROOM_EVENTS.ended:
|
|
5361
5369
|
return applyEnded(store, payload);
|
|
5362
|
-
case ROOM_EVENTS.recording:
|
|
5363
|
-
return applyRecording(store, payload);
|
|
5364
5370
|
case ROOM_EVENTS.chat:
|
|
5365
5371
|
return applyChat(store, payload);
|
|
5366
5372
|
case ROOM_EVENTS.moderation:
|
|
@@ -5440,9 +5446,9 @@ function applyWrapUp(store, payload, now) {
|
|
|
5440
5446
|
store.announceWrapUp(announcement);
|
|
5441
5447
|
return HANDLED;
|
|
5442
5448
|
}
|
|
5443
|
-
function
|
|
5449
|
+
function applyRecordingState(store, payload) {
|
|
5444
5450
|
const row = object(payload["recording"]);
|
|
5445
|
-
if (row === null) return ignored("
|
|
5451
|
+
if (row === null) return ignored("room state carries no recording");
|
|
5446
5452
|
const meetingId = text2(payload["meeting_id"]);
|
|
5447
5453
|
const meeting = store.snapshot().meeting;
|
|
5448
5454
|
if (meeting !== null && meetingId !== null && meetingId !== meeting.id) {
|
|
@@ -5524,19 +5530,6 @@ function applyModeration(store, payload, now) {
|
|
|
5524
5530
|
}
|
|
5525
5531
|
const kind = text2(payload["kind"]);
|
|
5526
5532
|
switch (kind) {
|
|
5527
|
-
case "lower-hands": {
|
|
5528
|
-
const raw = payload["identities"];
|
|
5529
|
-
const everyone = raw === "*";
|
|
5530
|
-
const named = new Set(
|
|
5531
|
-
Array.isArray(raw) ? raw.filter((value) => typeof value === "string") : []
|
|
5532
|
-
);
|
|
5533
|
-
for (const participant of snapshot.participants) {
|
|
5534
|
-
if (participant.handRaised && (everyone || named.has(participant.identity))) {
|
|
5535
|
-
store.setHand(participant.identity, false);
|
|
5536
|
-
}
|
|
5537
|
-
}
|
|
5538
|
-
return HANDLED;
|
|
5539
|
-
}
|
|
5540
5533
|
case "role": {
|
|
5541
5534
|
const identity = text2(payload["identity"]);
|
|
5542
5535
|
const role = text2(payload["role"]);
|
|
@@ -5630,7 +5623,6 @@ function noteTakerLabel(status) {
|
|
|
5630
5623
|
|
|
5631
5624
|
// src/core/room-driver.ts
|
|
5632
5625
|
var DATA_TOPICS = {
|
|
5633
|
-
hand: "mx.hand",
|
|
5634
5626
|
reaction: "mx.reaction",
|
|
5635
5627
|
chat: "mx.chat"
|
|
5636
5628
|
};
|
|
@@ -5654,6 +5646,11 @@ function SCREEN_SHARE_BLOCKED_REMEDY_FOR(remedy) {
|
|
|
5654
5646
|
return /administrator|policy/i.test(remedy) ? remedy : SCREEN_SHARE_BLOCKED_REMEDY;
|
|
5655
5647
|
}
|
|
5656
5648
|
var PARTICIPANT_ROLE_ATTRIBUTE = "matrx.participant.role";
|
|
5649
|
+
var PARTICIPANT_HAND_ATTRIBUTE = "matrx.hand";
|
|
5650
|
+
function handFrom(value) {
|
|
5651
|
+
const at = value === void 0 || value.length === 0 ? Number.NaN : Number(value);
|
|
5652
|
+
return Number.isFinite(at) ? { handRaised: true, handRaisedAt: at } : { handRaised: false, handRaisedAt: null };
|
|
5653
|
+
}
|
|
5657
5654
|
var PARTICIPANT_CAN_RECORD_ATTRIBUTE = "matrx.participant.can_record";
|
|
5658
5655
|
var CONNECTION_KIND_ATTRIBUTE = "matrx.participant.connection_kind";
|
|
5659
5656
|
var PARTICIPANT_STANDING_ATTRIBUTE = "matrx.participant.standing";
|
|
@@ -5707,7 +5704,10 @@ function projectParticipant(driver, joinedAt) {
|
|
|
5707
5704
|
cameraEnabled: driver.cameraEnabled,
|
|
5708
5705
|
screenSharing: driver.screenSharing,
|
|
5709
5706
|
speaking: false,
|
|
5710
|
-
|
|
5707
|
+
// S8: a hand is the SERVER's (`hand_raised_at` on the person row, `/moderate raise_hand`),
|
|
5708
|
+
// replicated as the `matrx.hand` attribute: epoch ms of the raise, "" when down. It is
|
|
5709
|
+
// therefore delivered to late joiners and survives refresh and reconnect.
|
|
5710
|
+
...handFrom(driver.attributes[PARTICIPANT_HAND_ATTRIBUTE]),
|
|
5711
5711
|
quality: "unknown",
|
|
5712
5712
|
joinedAt
|
|
5713
5713
|
};
|
|
@@ -5837,40 +5837,38 @@ function createRoomEngine(options) {
|
|
|
5837
5837
|
},
|
|
5838
5838
|
participants(list) {
|
|
5839
5839
|
const joinedAt = new Date(now()).toISOString();
|
|
5840
|
-
const before = new Set(store.snapshot().participants.map((p) => p.identity));
|
|
5841
5840
|
projectRoster(list, joinedAt);
|
|
5842
|
-
const snapshot = store.snapshot();
|
|
5843
|
-
const newcomer = snapshot.participants.some(
|
|
5844
|
-
(participant) => !participant.isLocal && !before.has(participant.identity)
|
|
5845
|
-
);
|
|
5846
|
-
const me = snapshot.participants.find((p) => p.identity === snapshot.localIdentity);
|
|
5847
|
-
if (newcomer && before.size > 0 && me?.handRaised === true) {
|
|
5848
|
-
void publish(DATA_TOPICS.hand, { raised: true, raisedAt: me.handRaisedAt ?? now() }).catch(
|
|
5849
|
-
() => void 0
|
|
5850
|
-
);
|
|
5851
|
-
}
|
|
5852
5841
|
},
|
|
5853
5842
|
participantLeft(who, reason) {
|
|
5854
5843
|
departures.set(who, reason);
|
|
5855
5844
|
},
|
|
5856
5845
|
roomMetadata(metadata) {
|
|
5857
|
-
let
|
|
5846
|
+
let parsed = {};
|
|
5858
5847
|
if (metadata.length > 0) {
|
|
5859
5848
|
try {
|
|
5860
|
-
const
|
|
5861
|
-
if (typeof
|
|
5862
|
-
const value = parsed.spotlight;
|
|
5863
|
-
if (typeof value === "string" && value.length > 0) spotlight = asParticipantIdentity(value);
|
|
5864
|
-
}
|
|
5849
|
+
const value = JSON.parse(metadata);
|
|
5850
|
+
if (typeof value === "object" && value !== null) parsed = value;
|
|
5865
5851
|
} catch {
|
|
5866
5852
|
report(
|
|
5867
5853
|
"warn",
|
|
5868
|
-
"meet: the room's metadata is not JSON, so
|
|
5869
|
-
"Only aidream writes room metadata; check services/meet/
|
|
5854
|
+
"meet: the room's metadata is not JSON, so the room state was not read from it",
|
|
5855
|
+
"Only aidream writes room metadata; check services/meet/room_state.py."
|
|
5870
5856
|
);
|
|
5871
5857
|
}
|
|
5872
5858
|
}
|
|
5873
|
-
|
|
5859
|
+
const key = (name) => {
|
|
5860
|
+
const value = parsed[name];
|
|
5861
|
+
return typeof value === "string" && value.length > 0 ? asParticipantIdentity(personOf(value)) : null;
|
|
5862
|
+
};
|
|
5863
|
+
const waiting = typeof parsed["waiting_count"] === "number" ? parsed["waiting_count"] : 0;
|
|
5864
|
+
const before = store.snapshot();
|
|
5865
|
+
const next = { spotlight: key("spotlight"), actingHost: key("acting_host"), presenter: key("presenter"), waitingCount: waiting };
|
|
5866
|
+
if (before.spotlight !== next.spotlight || before.actingHost !== next.actingHost || before.presenter !== next.presenter || before.waitingCount !== next.waitingCount) {
|
|
5867
|
+
store.patch(next);
|
|
5868
|
+
}
|
|
5869
|
+
if (parsed["recording"] !== void 0 && parsed["recording"] !== null) {
|
|
5870
|
+
applyRecordingState(store, { meeting_id: parsed["meeting_id"], recording: parsed["recording"] });
|
|
5871
|
+
}
|
|
5874
5872
|
},
|
|
5875
5873
|
activeSpeakers(identities) {
|
|
5876
5874
|
store.setSpeaking([...new Set(identities.map((who) => personOf(who)))]);
|
|
@@ -5972,13 +5970,6 @@ function createRoomEngine(options) {
|
|
|
5972
5970
|
}
|
|
5973
5971
|
const sender = personOf(from ?? "");
|
|
5974
5972
|
switch (topic) {
|
|
5975
|
-
case DATA_TOPICS.hand:
|
|
5976
|
-
store.setHand(
|
|
5977
|
-
sender,
|
|
5978
|
-
envelope.raised === true,
|
|
5979
|
-
typeof envelope.raisedAt === "number" ? envelope.raisedAt : now()
|
|
5980
|
-
);
|
|
5981
|
-
return;
|
|
5982
5973
|
case DATA_TOPICS.reaction:
|
|
5983
5974
|
if (typeof envelope.emoji === "string") {
|
|
5984
5975
|
store.addReaction({
|
|
@@ -6077,6 +6068,7 @@ function createRoomEngine(options) {
|
|
|
6077
6068
|
current = token;
|
|
6078
6069
|
lastServerUrl = token.serverUrl;
|
|
6079
6070
|
connectionPolicy = token.connectionPolicy ?? DEFAULT_CONNECTION_POLICY;
|
|
6071
|
+
if (token.leavePolicy !== void 0) store.patch({ leavePolicy: token.leavePolicy });
|
|
6080
6072
|
store.patch({
|
|
6081
6073
|
localIdentity: token.identity,
|
|
6082
6074
|
breakoutRoomId: token.breakoutRoomId ?? null,
|
|
@@ -6443,11 +6435,6 @@ function createRoomEngine(options) {
|
|
|
6443
6435
|
dismissShareNotice() {
|
|
6444
6436
|
if (store.snapshot().share.state === "refused") store.patch({ share: NO_SHARE });
|
|
6445
6437
|
},
|
|
6446
|
-
async raiseHand(raised) {
|
|
6447
|
-
const local = store.snapshot().localIdentity;
|
|
6448
|
-
if (local !== null) store.setHand(local, raised);
|
|
6449
|
-
await publish(DATA_TOPICS.hand, { raised, raisedAt: now() });
|
|
6450
|
-
},
|
|
6451
6438
|
async react(emoji) {
|
|
6452
6439
|
const local = store.snapshot().localIdentity;
|
|
6453
6440
|
const id = `${local ?? "local"}-${now()}`;
|
|
@@ -6576,6 +6563,8 @@ var MODERATION_ACTIONS = [
|
|
|
6576
6563
|
"ask_unmute",
|
|
6577
6564
|
"ask_all_unmute",
|
|
6578
6565
|
"spotlight",
|
|
6566
|
+
"present",
|
|
6567
|
+
"raise_hand",
|
|
6579
6568
|
"lower_hand",
|
|
6580
6569
|
"lower_all_hands",
|
|
6581
6570
|
"make_cohost",
|
|
@@ -6619,7 +6608,8 @@ function createInRoomClient(options) {
|
|
|
6619
6608
|
action: request.action,
|
|
6620
6609
|
...request.identity != null ? { identity: request.identity } : {},
|
|
6621
6610
|
...request.name !== void 0 ? { name: request.name } : {},
|
|
6622
|
-
...request.reason !== void 0 ? { reason: request.reason } : {}
|
|
6611
|
+
...request.reason !== void 0 ? { reason: request.reason } : {},
|
|
6612
|
+
...request.on !== void 0 ? { on: request.on } : {}
|
|
6623
6613
|
},
|
|
6624
6614
|
...hdrs !== void 0 ? { headers: hdrs } : {}
|
|
6625
6615
|
});
|
|
@@ -8473,16 +8463,20 @@ function useRoom() {
|
|
|
8473
8463
|
async () => requireEngine(engine, "toggleCamera").setCameraEnabled(!(local?.cameraEnabled ?? false)),
|
|
8474
8464
|
[engine, local]
|
|
8475
8465
|
),
|
|
8476
|
-
toggleScreenShare: (0, import_react4.useCallback)(
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
)
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
|
|
8466
|
+
toggleScreenShare: (0, import_react4.useCallback)(async () => {
|
|
8467
|
+
const on = !(local?.screenSharing ?? false);
|
|
8468
|
+
await requireEngine(engine, "toggleScreenShare").setScreenShareEnabled(on);
|
|
8469
|
+
const sharing = host?.store.snapshot().participants.find((p) => p.isLocal)?.screenSharing ?? false;
|
|
8470
|
+
if (host !== null && sharing === on) {
|
|
8471
|
+
await host.inRoom.moderate({ action: "present", on }).catch(() => void 0);
|
|
8472
|
+
}
|
|
8473
|
+
}, [engine, host, local]),
|
|
8474
|
+
// S8: a hand is SERVER state (`/moderate raise_hand · lower_hand`, server time), replicated
|
|
8475
|
+
// back as the `matrx.hand` attribute — no client sets its own hand on the wire.
|
|
8476
|
+
toggleHand: (0, import_react4.useCallback)(async () => {
|
|
8477
|
+
if (host === null) throw noRuntime("toggleHand");
|
|
8478
|
+
await host.inRoom.moderate({ action: local?.handRaised === true ? "lower_hand" : "raise_hand" });
|
|
8479
|
+
}, [host, local]),
|
|
8486
8480
|
react: (0, import_react4.useCallback)(
|
|
8487
8481
|
async (emoji) => requireEngine(engine, "react").react(emoji),
|
|
8488
8482
|
[engine]
|
|
@@ -8664,6 +8658,31 @@ function useWaiting() {
|
|
|
8664
8658
|
askAgain: (0, import_react4.useCallback)(async () => requireSession(session, "askAgain").askAgain(), [session])
|
|
8665
8659
|
};
|
|
8666
8660
|
}
|
|
8661
|
+
function useLeave() {
|
|
8662
|
+
const host = useMeetHost();
|
|
8663
|
+
const snapshot = useMeetSnapshot();
|
|
8664
|
+
const session = host?.meetings ?? null;
|
|
8665
|
+
const engine = host?.engine ?? null;
|
|
8666
|
+
const policy = snapshot?.leavePolicy ?? DEFAULT_LEAVE_POLICY;
|
|
8667
|
+
const participants = snapshot?.participants ?? [];
|
|
8668
|
+
const me = participants.find((p) => p.isLocal);
|
|
8669
|
+
const candidates = participants.filter((p) => !p.isLocal && !p.isAgent && p.role !== "viewer");
|
|
8670
|
+
const choices = leaveChoices({ policy, role: me?.role ?? null, othersPresent: candidates.length > 0 });
|
|
8671
|
+
return {
|
|
8672
|
+
choices,
|
|
8673
|
+
policy,
|
|
8674
|
+
candidates,
|
|
8675
|
+
leave: (0, import_react4.useCallback)(async () => requireEngine(engine, "leave").leave(), [engine]),
|
|
8676
|
+
endForAll: (0, import_react4.useCallback)(async () => requireSession(session, "endForAll").hostLeave("end_for_all"), [session]),
|
|
8677
|
+
assignAndLeave: (0, import_react4.useCallback)(
|
|
8678
|
+
async (person) => {
|
|
8679
|
+
await requireSession(session, "assignAndLeave").hostLeave({ assignTo: String(person.identity) });
|
|
8680
|
+
await requireEngine(engine, "leave").leave();
|
|
8681
|
+
},
|
|
8682
|
+
[session, engine]
|
|
8683
|
+
)
|
|
8684
|
+
};
|
|
8685
|
+
}
|
|
8667
8686
|
function useRecording() {
|
|
8668
8687
|
const host = useMeetHost();
|
|
8669
8688
|
const snapshot = useMeetSnapshot();
|
|
@@ -11587,19 +11606,75 @@ function ControlBar({ onLeave }) {
|
|
|
11587
11606
|
] }) : null
|
|
11588
11607
|
] }) }) : null
|
|
11589
11608
|
] }),
|
|
11590
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
11591
|
-
|
|
11609
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LeaveControl, { onLeave })
|
|
11610
|
+
] })
|
|
11611
|
+
] });
|
|
11612
|
+
}
|
|
11613
|
+
var LEAVE_WORDS = {
|
|
11614
|
+
leave_or_end: { leave: "Leave call", assign_and_leave: "Assign a new host", end_for_all: "End call for everyone" },
|
|
11615
|
+
must_assign_or_end: { leave: "Leave meeting", assign_and_leave: "Assign a new host", end_for_all: "End meeting for all" },
|
|
11616
|
+
leave_only: { leave: "Leave", assign_and_leave: "Assign a new host", end_for_all: "End meeting" }
|
|
11617
|
+
};
|
|
11618
|
+
function LeaveControl({ onLeave }) {
|
|
11619
|
+
const leave = useLeave();
|
|
11620
|
+
const [open, setOpen] = (0, import_react10.useState)("none");
|
|
11621
|
+
const [failure, setFailure] = (0, import_react10.useState)(null);
|
|
11622
|
+
const words = LEAVE_WORDS[leave.policy.hostLeavePrompt];
|
|
11623
|
+
const run = (work, leaving) => {
|
|
11624
|
+
setFailure(null);
|
|
11625
|
+
void work().then(() => {
|
|
11626
|
+
setOpen("none");
|
|
11627
|
+
if (leaving) onLeave?.();
|
|
11628
|
+
}).catch((error) => setFailure(error instanceof Error ? error.message : String(error)));
|
|
11629
|
+
};
|
|
11630
|
+
const leaveNow = () => run(leave.leave, true);
|
|
11631
|
+
const endNow = () => run(leave.endForAll, false);
|
|
11632
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "mx-meet__anchor", children: [
|
|
11633
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
11634
|
+
ControlButton,
|
|
11635
|
+
{
|
|
11636
|
+
label: "Leave",
|
|
11637
|
+
danger: true,
|
|
11638
|
+
active: open !== "none",
|
|
11639
|
+
onClick: () => {
|
|
11640
|
+
if (leave.choices.length === 1 && leave.choices[0] === "leave") leaveNow();
|
|
11641
|
+
else setOpen(open === "none" ? "menu" : "none");
|
|
11642
|
+
},
|
|
11643
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PhoneOffIcon, {})
|
|
11644
|
+
}
|
|
11645
|
+
),
|
|
11646
|
+
open !== "none" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Popover, { label: open === "assign" ? words.assign_and_leave : "Leave", onClose: () => setOpen("none"), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mx-meet__menu", "data-meet-leave-menu": leave.policy.hostLeavePrompt, children: [
|
|
11647
|
+
open === "menu" ? leave.choices.map((choice) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
11648
|
+
"button",
|
|
11592
11649
|
{
|
|
11593
|
-
|
|
11594
|
-
danger:
|
|
11650
|
+
type: "button",
|
|
11651
|
+
className: choice === "end_for_all" ? "mx-meet__menu-item mx-meet__menu-item--danger" : "mx-meet__menu-item",
|
|
11595
11652
|
onClick: () => {
|
|
11596
|
-
|
|
11597
|
-
|
|
11653
|
+
if (choice === "leave") leaveNow();
|
|
11654
|
+
else if (choice === "assign_and_leave") setOpen("assign");
|
|
11655
|
+
else if (leave.policy.endConfirm) setOpen("confirm");
|
|
11656
|
+
else endNow();
|
|
11598
11657
|
},
|
|
11599
|
-
children:
|
|
11600
|
-
}
|
|
11601
|
-
|
|
11602
|
-
|
|
11658
|
+
children: words[choice]
|
|
11659
|
+
},
|
|
11660
|
+
choice
|
|
11661
|
+
)) : null,
|
|
11662
|
+
open === "assign" ? leave.candidates.map((person) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
11663
|
+
"button",
|
|
11664
|
+
{
|
|
11665
|
+
type: "button",
|
|
11666
|
+
className: "mx-meet__menu-item",
|
|
11667
|
+
onClick: () => run(() => leave.assignAndLeave(person), true),
|
|
11668
|
+
children: person.displayName
|
|
11669
|
+
},
|
|
11670
|
+
String(person.identity)
|
|
11671
|
+
)) : null,
|
|
11672
|
+
open === "confirm" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
11673
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "mx-meet__menu-item mx-meet__menu-item--danger", onClick: endNow, children: words.end_for_all }),
|
|
11674
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "mx-meet__menu-item", onClick: () => setOpen("menu"), children: "Cancel" })
|
|
11675
|
+
] }) : null,
|
|
11676
|
+
failure !== null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__menu-note", role: "alert", children: failure }) : null
|
|
11677
|
+
] }) }) : null
|
|
11603
11678
|
] });
|
|
11604
11679
|
}
|
|
11605
11680
|
function useUnreadChat(open) {
|