@ai-matrx/meet 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.cjs CHANGED
@@ -55,6 +55,7 @@ __export(react_exports, {
55
55
  LISTEN_ONLY_NOTICE: () => LISTEN_ONLY_NOTICE,
56
56
  MEETING_INVITE_KIND: () => MEETING_INVITE_KIND,
57
57
  MEETING_INVITE_VERSION: () => MEETING_INVITE_VERSION,
58
+ MEETING_PASS_HEADER: () => MEETING_PASS_HEADER,
58
59
  MEETING_RECORD_GRACE_MS: () => MEETING_RECORD_GRACE_MS,
59
60
  MEET_ANSWER_CONTEXT_EVENT: () => MEET_ANSWER_CONTEXT_EVENT,
60
61
  MEET_ANSWER_EVENTS: () => MEET_ANSWER_EVENTS,
@@ -75,12 +76,12 @@ __export(react_exports, {
75
76
  ORGANIZATION_HEADER: () => ORGANIZATION_HEADER,
76
77
  PARTICIPANT_CAN_RECORD_ATTRIBUTE: () => PARTICIPANT_CAN_RECORD_ATTRIBUTE,
77
78
  PARTICIPANT_ROLE_ATTRIBUTE: () => PARTICIPANT_ROLE_ATTRIBUTE,
79
+ PARTICIPANT_STANDING_ATTRIBUTE: () => PARTICIPANT_STANDING_ATTRIBUTE,
78
80
  REACTION_TTL_MS: () => REACTION_TTL_MS,
79
81
  REFUSED_ABSENCE: () => REFUSED_ABSENCE,
80
82
  ROLE_RANK: () => ROLE_RANK,
81
83
  ROOM_EVENTS: () => ROOM_EVENTS,
82
84
  ROOM_EVENT_PREFIX: () => ROOM_EVENT_PREFIX,
83
- ROOM_TOKEN_HEADER: () => ROOM_TOKEN_HEADER,
84
85
  RPCS: () => RPCS,
85
86
  RecordingPlayer: () => RecordingPlayer,
86
87
  TABLES: () => TABLES,
@@ -152,6 +153,7 @@ __export(react_exports, {
152
153
  isGuest: () => isGuest,
153
154
  isGuestIdentity: () => isGuestIdentity,
154
155
  isHostRole: () => isHostRole,
156
+ isLinkFollower: () => isLinkFollower,
155
157
  isListenOnly: () => isListenOnly,
156
158
  isNoteTaker: () => isNoteTaker,
157
159
  isRealName: () => isRealName,
@@ -170,6 +172,7 @@ __export(react_exports, {
170
172
  meetingInviteAction: () => meetingInviteAction,
171
173
  meetingLength: () => meetingLength,
172
174
  meetingLink: () => meetingLink,
175
+ meetingPassHeaders: () => meetingPassHeaders,
173
176
  meetingPath: () => meetingPath,
174
177
  meetingRecordCache: () => meetingRecordCache,
175
178
  meetingSlug: () => meetingSlug,
@@ -214,6 +217,7 @@ __export(react_exports, {
214
217
  recordingLabel: () => recordingLabel,
215
218
  recordingNotice: () => recordingNotice,
216
219
  recordingOffsetMs: () => recordingOffsetMs,
220
+ rememberedMeetingPass: () => rememberedMeetingPass,
217
221
  roleOf: () => roleOf,
218
222
  roomTopic: () => roomTopic,
219
223
  rootAttributes: () => rootAttributes,
@@ -294,11 +298,18 @@ var MeetError = class extends Error {
294
298
  /** What to DO. Rendered to the user for the device codes. */
295
299
  remedy;
296
300
  cause;
297
- constructor(code, message, remedy, cause) {
301
+ /**
302
+ * The join gate's reason code (CORE-DESIGN §2.5) when the server named one: `not_found`,
303
+ * `cancelled`, `ended`, `locked`, `removed`, `lobby_rejects`, `not_invited`… The phase
304
+ * renders `refused:<reason>` (or `ended`) from it — never from the HTTP status.
305
+ */
306
+ reason;
307
+ constructor(code, message, remedy, cause, reason) {
298
308
  super(message);
299
309
  this.name = "MeetError";
300
310
  this.code = code;
301
311
  this.remedy = remedy;
312
+ this.reason = reason ?? null;
302
313
  if (cause !== void 0) this.cause = cause;
303
314
  }
304
315
  /** True when retrying after the host re-establishes a session is the fix. */
@@ -516,6 +527,17 @@ function createWebRoomTokenStorage(onDiagnostic) {
516
527
  }
517
528
  };
518
529
  }
530
+ function rememberedMeetingPass(roomName, storage = createWebRoomTokenStorage()) {
531
+ const raw = storage.read(roomName);
532
+ if (raw === null) return null;
533
+ try {
534
+ const parsed = JSON.parse(raw);
535
+ if (parsed.standing !== "guest") return null;
536
+ return typeof parsed.meetingPass === "string" && parsed.meetingPass.length > 0 ? parsed.meetingPass : null;
537
+ } catch {
538
+ return null;
539
+ }
540
+ }
519
541
  var MEET_ROUTES = {
520
542
  token: "/api/v1/meet/token",
521
543
  recordingStart: "/api/v1/meet/recording/start",
@@ -529,7 +551,7 @@ var MEET_ROUTES = {
529
551
  /**
530
552
  * THE POST-MEETING RECORD FOR A READER WITH NO DATABASE (MRF-1). A `GET`,
531
553
  * authorized by the room token this device already holds, carried in the
532
- * `x-meet-room-token` header — never a query parameter, because a bearer
554
+ * `x-meet-pass` header — never a query parameter, because a bearer
533
555
  * credential in a URL lands in access logs, referrers and history.
534
556
  */
535
557
  record: "/api/v1/meet/record",
@@ -537,7 +559,7 @@ var MEET_ROUTES = {
537
559
  recordAccess: "/api/v1/meet/record/access",
538
560
  /**
539
561
  * KEEP YOUR NOTES (2026-10-01): a guest who just created an account presents
540
- * their kept pass in `x-meet-room-token` with their new session, and the
562
+ * their kept pass in `x-meet-pass` with their new session, and the
541
563
  * meeting they attended becomes theirs to read. Idempotent; never a grant.
542
564
  */
543
565
  claim: "/api/v1/meet/claim",
@@ -559,7 +581,7 @@ var MEET_ROUTES = {
559
581
  * Meet wave 2: EVERY in-meeting host power (mute, stop video, mute all, ask to
560
582
  * unmute, spotlight, lower hands, co-host, hand over, rename, remove, report).
561
583
  * Decided by the server from the meeting itself; a guest's pass rides
562
- * `x-meet-room-token`.
584
+ * `x-meet-pass`.
563
585
  */
564
586
  moderate: "/api/v1/meet/moderate",
565
587
  /** Meet wave 2: the SAVED chat — `POST` sends to everyone, `GET ?meeting_id=` reads history. */
@@ -575,7 +597,11 @@ var MEET_ROUTES = {
575
597
  function meetingPath(template, meetingId) {
576
598
  return template.replace("{meeting_id}", encodeURIComponent(meetingId));
577
599
  }
578
- var ROOM_TOKEN_HEADER = "x-meet-room-token";
600
+ var MEETING_PASS_HEADER = "x-meet-pass";
601
+ function meetingPassHeaders(token) {
602
+ const pass = token?.meetingPass ?? null;
603
+ return pass !== null && pass.length > 0 ? { [MEETING_PASS_HEADER]: pass } : {};
604
+ }
579
605
  var REFRESH_RATIO = 0.8;
580
606
  function readString(source, key) {
581
607
  const value = source[key];
@@ -585,7 +611,12 @@ function readBoolean(source, key, fallback) {
585
611
  const value = source[key];
586
612
  return typeof value === "boolean" ? value : fallback;
587
613
  }
588
- var TOKEN_ROLES = ["host", "cohost", "participant", "guest"];
614
+ var TOKEN_STANDINGS = ["member", "invited", "outsider", "guest"];
615
+ function readStanding(source, key) {
616
+ const value = source[key];
617
+ return TOKEN_STANDINGS.includes(value) ? value : null;
618
+ }
619
+ var TOKEN_ROLES = ["host", "cohost", "presenter", "participant", "viewer"];
589
620
  function readRole(source, key) {
590
621
  const value = source[key];
591
622
  return TOKEN_ROLES.includes(value) ? value : null;
@@ -628,7 +659,12 @@ function parseRoomToken(body, roomName) {
628
659
  // Deriving the role from what DID arrive keeps a host a host against a
629
660
  // server that has not landed MRI-A11 — and never invents a host from
630
661
  // silence, because both fallbacks below grant nothing.
631
- role: readRole(payload, "role") ?? (isHost ? "host" : identity.startsWith("guest:") ? "guest" : "participant"),
662
+ // A word this package does not know grants nothing: `participant`, never a host.
663
+ role: readRole(payload, "role") ?? (isHost ? "host" : "participant"),
664
+ standing: readStanding(payload, "standing"),
665
+ meetingPass: readString(payload, "meeting_pass"),
666
+ meetingPassExpiresAt: readString(payload, "meeting_pass_expires_at"),
667
+ sessionId: readString(payload, "session_id"),
632
668
  lobby: readBoolean(payload, "lobby", false),
633
669
  breakoutRoomId: readString(payload, "breakout_room_id") ?? null
634
670
  };
@@ -639,7 +675,7 @@ function createTokenClient(options) {
639
675
  const storage = options.storage;
640
676
  function remember(token) {
641
677
  if (storage === void 0) return;
642
- if (!token.identity.startsWith("guest:")) return;
678
+ if (token.standing !== "guest") return;
643
679
  storage.write(token.roomName, JSON.stringify(token));
644
680
  }
645
681
  function recall(roomName) {
@@ -697,22 +733,28 @@ function createTokenClient(options) {
697
733
  throw new MeetError(
698
734
  "forbidden",
699
735
  said?.message ?? "You can't join this meeting.",
700
- said?.remedy ?? "Ask the person who shared the link to let you in, then open the link again."
736
+ said?.remedy ?? "Ask the person who shared the link to let you in, then open the link again.",
737
+ void 0,
738
+ said?.reason ?? null
701
739
  );
702
740
  }
703
741
  if (response.status === 404) {
704
742
  throw new MeetError(
705
743
  "not-found",
706
744
  "meet.token: no such meeting",
707
- "The link is wrong or the meeting was deleted. Show the 'meeting not found' screen; a durable link that 404s is never a retry."
745
+ "The link is wrong or the meeting was deleted. Show the 'meeting not found' screen; a durable link that 404s is never a retry.",
746
+ void 0,
747
+ "not_found"
708
748
  );
709
749
  }
710
750
  if (response.status === 410) {
711
- const reason = (await serverSentence(response))?.message ?? "This meeting was cancelled.";
751
+ const said = await serverSentence(response);
712
752
  throw new MeetError(
713
753
  "cancelled",
714
- reason,
715
- "Nobody can join a cancelled meeting. Show the cancelled screen with this sentence; ask the host to schedule a new one."
754
+ said?.message ?? "This meeting was cancelled.",
755
+ "Nobody can join a cancelled meeting. Show the cancelled screen with this sentence; ask the host to schedule a new one.",
756
+ void 0,
757
+ said?.reason ?? "cancelled"
716
758
  );
717
759
  }
718
760
  if (response.status === 423) {
@@ -720,7 +762,9 @@ function createTokenClient(options) {
720
762
  throw new MeetError(
721
763
  "room-locked",
722
764
  said?.message ?? "The meeting is locked.",
723
- said?.remedy ?? "The host locked the room. Ask them to unlock it, then join again."
765
+ said?.remedy ?? "The host locked the room. Ask them to unlock it, then join again.",
766
+ void 0,
767
+ said?.reason ?? "locked"
724
768
  );
725
769
  }
726
770
  if (response.status === 503) {
@@ -789,6 +833,10 @@ function placeholder(roomName) {
789
833
  canRecord: false,
790
834
  isHost: false,
791
835
  role: "participant",
836
+ standing: null,
837
+ meetingPass: null,
838
+ meetingPassExpiresAt: null,
839
+ sessionId: null,
792
840
  lobby: false,
793
841
  breakoutRoomId: null
794
842
  };
@@ -801,7 +849,8 @@ async function serverSentence(response) {
801
849
  const message = typeof source.user_message === "string" && source.user_message.trim() !== "" ? source.user_message : typeof source.message === "string" && source.message.trim() !== "" ? source.message : null;
802
850
  if (message === null) return null;
803
851
  const remedy = typeof source.remedy === "string" && source.remedy.trim() !== "" ? source.remedy : void 0;
804
- return { message, remedy };
852
+ const reason = typeof source.reason === "string" && source.reason !== "" ? source.reason : null;
853
+ return { message, remedy, reason };
805
854
  } catch {
806
855
  return null;
807
856
  }
@@ -990,7 +1039,7 @@ function createMeetAi(options) {
990
1039
  operation: "meet.ai.ask",
991
1040
  // A GUEST MAY ASK. The server decides whether it can answer.
992
1041
  requireAuth: false,
993
- ...roomToken !== null ? { headers: { [ROOM_TOKEN_HEADER]: roomToken } } : {},
1042
+ ...roomToken !== null ? { headers: { [MEETING_PASS_HEADER]: roomToken } } : {},
994
1043
  ...signal !== void 0 ? { signal } : {}
995
1044
  });
996
1045
  if (!response.ok) {
@@ -1225,11 +1274,15 @@ function isGuest(identity) {
1225
1274
  return identity.userId === null;
1226
1275
  }
1227
1276
  var ROLE_RANK = {
1228
- host: 3,
1229
- cohost: 2,
1277
+ host: 4,
1278
+ cohost: 3,
1279
+ presenter: 2,
1230
1280
  participant: 1,
1231
- guest: 0
1281
+ viewer: 0
1232
1282
  };
1283
+ function isLinkFollower(standing) {
1284
+ return standing === "guest" || standing === "outsider";
1285
+ }
1233
1286
  function isHostRole(role) {
1234
1287
  return role === "host" || role === "cohost";
1235
1288
  }
@@ -2136,15 +2189,15 @@ var CAPTION_LANGUAGES = [
2136
2189
  { tag: "id", name: "Indonesian" },
2137
2190
  { tag: "sv", name: "Swedish" }
2138
2191
  ];
2139
- async function loadMeetingActivities(api, meetingId, roomToken = null) {
2192
+ async function loadMeetingActivities(api, meetingId, meetingPass = null) {
2140
2193
  let response;
2141
2194
  try {
2142
2195
  response = await api.request({
2143
2196
  path: `${MEET_ROUTES.collab}?meeting_id=${encodeURIComponent(meetingId)}`,
2144
2197
  method: "GET",
2145
2198
  operation: "meet.loadMeetingActivities",
2146
- requireAuth: roomToken === null,
2147
- ...roomToken !== null ? { headers: { [ROOM_TOKEN_HEADER]: roomToken } } : {}
2199
+ requireAuth: meetingPass === null,
2200
+ ...meetingPass !== null ? { headers: { [MEETING_PASS_HEADER]: meetingPass } } : {}
2148
2201
  });
2149
2202
  } catch (error) {
2150
2203
  return {
@@ -2241,6 +2294,7 @@ var DEFAULT_EFFECTS = {
2241
2294
  };
2242
2295
  var NO_GRANTS = {
2243
2296
  role: "participant",
2297
+ standing: null,
2244
2298
  canRecord: false,
2245
2299
  canPublish: false,
2246
2300
  canSubscribe: false
@@ -2287,6 +2341,11 @@ function effectiveRole(snapshot) {
2287
2341
  const fromToken = snapshot.grants.role;
2288
2342
  return ROLE_RANK[fromRoster] >= ROLE_RANK[fromToken] ? fromRoster : fromToken;
2289
2343
  }
2344
+ function effectiveStanding(snapshot) {
2345
+ if (snapshot.grants.standing != null) return snapshot.grants.standing;
2346
+ const me = snapshot.participants.find((p) => p.identity === snapshot.localIdentity);
2347
+ return me?.standing ?? null;
2348
+ }
2290
2349
  var REACTION_TTL_MS = 5e3;
2291
2350
  var CHAT_LIMIT = 200;
2292
2351
  function createMeetStore(initial = {}) {
@@ -2880,7 +2939,6 @@ var RPCS = {
2880
2939
  meetingBySlug: "meet_meeting_by_slug",
2881
2940
  admit: "meet_admit_participant",
2882
2941
  setLock: "meet_set_lock",
2883
- endMeeting: "meet_end_meeting",
2884
2942
  recordConsent: "meet_record_consent",
2885
2943
  /*
2886
2944
  * ── MEET WAVE 1 — management (0.8). Every write is a SECURITY DEFINER door
@@ -3294,7 +3352,7 @@ function createMeetRepository(options) {
3294
3352
  const operation = "meet.projectAttendee";
3295
3353
  const role = text(row, "role");
3296
3354
  const admission = text(row, "admission_state");
3297
- const known = ["host", "cohost", "participant", "guest"];
3355
+ const known = ["host", "cohost", "presenter", "participant", "viewer"];
3298
3356
  const states = ["knocking", "admitted", "denied", "removed"];
3299
3357
  const userId = text(row, "participant_user_id");
3300
3358
  const identity = requireText(row, "identity", operation);
@@ -3609,16 +3667,6 @@ function createMeetRepository(options) {
3609
3667
  );
3610
3668
  return projectMeeting(row);
3611
3669
  },
3612
- async endMeeting(meetingId, byUserId) {
3613
- const row = await guard(
3614
- "meet.endMeeting",
3615
- () => db.rpc(RPCS.endMeeting, {
3616
- p_meeting_id: meetingId,
3617
- p_by_user_id: byUserId
3618
- })
3619
- );
3620
- return projectMeeting(row);
3621
- },
3622
3670
  async transcript(meetingId, limit = 1e3) {
3623
3671
  const response = await db.from(TABLES.transcripts).select(SEGMENT_COLUMNS).eq("meeting_id", meetingId).order("started_at", { ascending: true }).order("id", { ascending: true }).limit(limit);
3624
3672
  if (response.error !== null) throw normalizeMeetError(response.error, "meet.transcript");
@@ -4062,7 +4110,7 @@ function applyModeration(store, payload, now) {
4062
4110
  return ignored(`a moderation kind this version does not know: ${String(kind)}`);
4063
4111
  }
4064
4112
  }
4065
- var ROLES = ["host", "cohost", "participant", "guest"];
4113
+ var ROLES = ["host", "cohost", "presenter", "participant", "viewer"];
4066
4114
 
4067
4115
  // src/core/note-taker.ts
4068
4116
  var NOTE_TAKER_IDENTITY_PREFIX = "agent:note_taker:";
@@ -4147,7 +4195,12 @@ var TRANSCRIPTION_ATTRIBUTES = {
4147
4195
  // src/core/room.ts
4148
4196
  var PARTICIPANT_ROLE_ATTRIBUTE = "matrx.participant.role";
4149
4197
  var PARTICIPANT_CAN_RECORD_ATTRIBUTE = "matrx.participant.can_record";
4150
- var KNOWN_ROLES = ["host", "cohost", "participant", "guest"];
4198
+ var PARTICIPANT_STANDING_ATTRIBUTE = "matrx.participant.standing";
4199
+ var KNOWN_STANDINGS = ["member", "invited", "outsider", "guest"];
4200
+ function parseStanding(value) {
4201
+ return KNOWN_STANDINGS.includes(value) ? value : null;
4202
+ }
4203
+ var KNOWN_ROLES = ["host", "cohost", "presenter", "participant", "viewer"];
4151
4204
  function parseRole(value) {
4152
4205
  return KNOWN_ROLES.includes(value) ? value : "participant";
4153
4206
  }
@@ -4181,6 +4234,9 @@ function projectParticipant(driver, joinedAt) {
4181
4234
  // ATTRIBUTE FIRST, metadata second — see the constants above. Both are the
4182
4235
  // server's; the attribute is simply the one that always arrives.
4183
4236
  role: parseRole(driver.attributes[PARTICIPANT_ROLE_ATTRIBUTE] ?? metadata.role),
4237
+ standing: parseStanding(
4238
+ driver.attributes[PARTICIPANT_STANDING_ATTRIBUTE] ?? metadata.standing
4239
+ ),
4184
4240
  canRecord: driver.attributes[PARTICIPANT_CAN_RECORD_ATTRIBUTE] === "true" || metadata.can_record === true,
4185
4241
  isLocal: driver.isLocal,
4186
4242
  isAgent: metadata.is_agent === true,
@@ -4253,7 +4309,7 @@ function createRoomEngine(options) {
4253
4309
  const normalized = normalizeMeetError(error, operation);
4254
4310
  store.patch({
4255
4311
  phase: "failed",
4256
- failure: { message: normalized.message, remedy: normalized.remedy }
4312
+ failure: { message: normalized.message, remedy: normalized.remedy, reason: normalized.reason }
4257
4313
  });
4258
4314
  report(
4259
4315
  normalized.code === "session-unavailable" ? "warn" : "error",
@@ -4457,6 +4513,7 @@ function createRoomEngine(options) {
4457
4513
  breakoutRoomId: token.breakoutRoomId ?? null,
4458
4514
  grants: {
4459
4515
  role: token.role,
4516
+ standing: token.standing,
4460
4517
  canRecord: token.canRecord,
4461
4518
  canPublish: token.canPublish,
4462
4519
  canSubscribe: token.canSubscribe
@@ -4802,7 +4859,7 @@ function createInRoomClient(options) {
4802
4859
  }
4803
4860
  function headers() {
4804
4861
  const token = options.resolveRoomToken();
4805
- return token === null ? void 0 : { [ROOM_TOKEN_HEADER]: token };
4862
+ return token === null ? void 0 : { [MEETING_PASS_HEADER]: token };
4806
4863
  }
4807
4864
  function refusal2(response, operation, remedy) {
4808
4865
  return refusalFromResponse(response, operation, remedy);
@@ -5563,8 +5620,8 @@ function MeetRuntime(props) {
5563
5620
  const roomName = store.snapshot().meeting?.roomName;
5564
5621
  if (roomName === void 0) return null;
5565
5622
  const active = engine.token();
5566
- if (active?.roomName === roomName && active.token.length > 0) return active.token;
5567
- return tokens.remembered(roomName)?.token ?? null;
5623
+ if (active?.roomName === roomName && active.meetingPass) return active.meetingPass;
5624
+ return tokens.remembered(roomName)?.meetingPass ?? null;
5568
5625
  };
5569
5626
  const ai = createMeetAi({ api, store, resolveRoomToken });
5570
5627
  const inRoom = createInRoomClient({ api, store, resolveRoomToken });
@@ -5736,6 +5793,10 @@ function useLocalUserId() {
5736
5793
  var import_react3 = require("react");
5737
5794
 
5738
5795
  // src/core/observation.ts
5796
+ function observedRole(role, standing) {
5797
+ if (role === "host" || role === "cohost") return role;
5798
+ return isLinkFollower(standing) ? "guest" : "participant";
5799
+ }
5739
5800
  function observedDevice(track) {
5740
5801
  if (track.enabled) return "on";
5741
5802
  const refused = track.unavailable;
@@ -5763,6 +5824,8 @@ function observedPhase(input) {
5763
5824
  const raw = snapshot.phase;
5764
5825
  const live = raw === "connected" || raw === "reconnecting";
5765
5826
  if (endedRecord(snapshot, input.meeting ?? null) && !live) return "ended";
5827
+ const reason = raw === "failed" ? snapshot.failure?.reason ?? null : null;
5828
+ if (reason !== null) return reason === "ended" ? "ended" : `refused:${reason}`;
5766
5829
  switch (raw) {
5767
5830
  case "idle":
5768
5831
  case "failed":
@@ -5783,12 +5846,13 @@ function observe(input) {
5783
5846
  const { snapshot } = input;
5784
5847
  const phase = observedPhase(input);
5785
5848
  const inCall = phase === "in_call";
5786
- const role = inCall && snapshot !== null ? effectiveRole(snapshot) : "none";
5787
- const canAdmit = role !== "none" && ADMITTER_ROLES.has(role);
5849
+ const actual = inCall && snapshot !== null ? effectiveRole(snapshot) : "none";
5850
+ const canAdmit = actual !== "none" && ADMITTER_ROLES.has(actual);
5851
+ const role = actual === "none" || snapshot === null ? "none" : observedRole(actual, effectiveStanding(snapshot));
5788
5852
  const deviceInPlay = phase === "joining" || inCall;
5789
5853
  return {
5790
5854
  phase,
5791
- reason: null,
5855
+ reason: phase.startsWith("refused:") ? phase.slice("refused:".length) : null,
5792
5856
  role,
5793
5857
  connection: snapshot?.phase === "reconnecting" ? "reconnecting" : "stable",
5794
5858
  hostPresent: inCall && snapshot !== null ? snapshot.participants.some((p) => ADMITTER_ROLES.has(p.role)) : null,
@@ -5854,7 +5918,7 @@ function participantAttributes(p) {
5854
5918
  "data-meet-participant": "",
5855
5919
  "data-meet-participant-identity": p.identity,
5856
5920
  "data-meet-participant-name": p.displayName,
5857
- "data-meet-participant-role": p.role,
5921
+ "data-meet-participant-role": observedRole(p.role, p.standing),
5858
5922
  "data-meet-participant-self": String(p.isLocal)
5859
5923
  };
5860
5924
  const quality = observedQuality(p.quality);
@@ -6183,7 +6247,7 @@ function summarizeMeetingRecordRestrictions(restrictions) {
6183
6247
  async function loadGuestMeetingRecord(args) {
6184
6248
  const { api, repository, meetingId, meeting, roomToken } = args;
6185
6249
  const session = args.session === true;
6186
- if (roomToken === null && !session) {
6250
+ if (roomToken?.meetingPass == null && !session) {
6187
6251
  return refusedBundle(
6188
6252
  meeting,
6189
6253
  "This meeting's record is only readable by the people who were in it.",
@@ -6193,12 +6257,12 @@ async function loadGuestMeetingRecord(args) {
6193
6257
  let response;
6194
6258
  try {
6195
6259
  response = await api.request({
6196
- path: `${MEET_ROUTES.record}?meeting_id=${encodeURIComponent(meetingId)}`,
6260
+ path: `${MEET_ROUTES.record}?meeting_id=${encodeURIComponent(meetingId)}` + (args.sessionId ? `&session_id=${encodeURIComponent(args.sessionId)}` : ""),
6197
6261
  method: "GET",
6198
6262
  // A GUEST HAS NO SESSION AND IS STILL A FIRST-CLASS READER (D6).
6199
6263
  requireAuth: session,
6200
6264
  operation: "meet.record",
6201
- headers: roomToken === null ? {} : { [ROOM_TOKEN_HEADER]: roomToken.token }
6265
+ headers: roomToken?.meetingPass != null ? { [MEETING_PASS_HEADER]: roomToken.meetingPass } : {}
6202
6266
  });
6203
6267
  } catch (error) {
6204
6268
  return refusedBundle(
@@ -7405,7 +7469,6 @@ function kindOf(person) {
7405
7469
  if (person.isAgent) return "assistant";
7406
7470
  if (person.role === "host") return "host";
7407
7471
  if (person.role === "cohost") return "cohost";
7408
- if (person.role === "guest") return person.userId !== null ? "signed-in guest" : "guest";
7409
7472
  if (person.userId === null) return "guest";
7410
7473
  return "member";
7411
7474
  }
@@ -7690,7 +7753,7 @@ function meetingLength(meeting) {
7690
7753
  if (start === null || end === null || end < start) return null;
7691
7754
  return (0, import_format2.formatDurationMs)(end - start, { style: "long" });
7692
7755
  }
7693
- async function loadMeetingChat(api, meetingId, roomToken = null) {
7756
+ async function loadMeetingChat(api, meetingId, meetingPass = null) {
7694
7757
  const operation = "meet.loadMeetingChat";
7695
7758
  let response;
7696
7759
  try {
@@ -7698,8 +7761,8 @@ async function loadMeetingChat(api, meetingId, roomToken = null) {
7698
7761
  path: `${MEET_ROUTES.chat}?meeting_id=${encodeURIComponent(meetingId)}`,
7699
7762
  method: "GET",
7700
7763
  operation,
7701
- requireAuth: roomToken === null,
7702
- ...roomToken !== null ? { headers: { [ROOM_TOKEN_HEADER]: roomToken } } : {}
7764
+ requireAuth: meetingPass === null,
7765
+ ...meetingPass !== null ? { headers: { [MEETING_PASS_HEADER]: meetingPass } } : {}
7703
7766
  });
7704
7767
  } catch (error) {
7705
7768
  return {
@@ -9172,10 +9235,13 @@ function RecordingIndicator() {
9172
9235
  }
9173
9236
  );
9174
9237
  }
9175
- function RoleBadge({ role }) {
9238
+ function RoleBadge({
9239
+ role,
9240
+ standing
9241
+ }) {
9176
9242
  if (role === "host") return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "mx-meet__badge", children: "Host" });
9177
9243
  if (role === "cohost") return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "mx-meet__badge", children: "Co-host" });
9178
- if (role === "guest") return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "mx-meet__badge", children: "Guest" });
9244
+ if (isLinkFollower(standing)) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "mx-meet__badge", children: "Guest" });
9179
9245
  return null;
9180
9246
  }
9181
9247
  function ParticipantTile({
@@ -9225,7 +9291,7 @@ function ParticipantTile({
9225
9291
  participant.displayName,
9226
9292
  participant.isLocal ? " (you)" : "",
9227
9293
  participant.isAgent ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "mx-meet__badge", children: "AI" }) : null,
9228
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RoleBadge, { role: participant.role })
9294
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RoleBadge, { role: participant.role, standing: participant.standing })
9229
9295
  ] }),
9230
9296
  !participant.micEnabled ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MicOffIcon, { width: 14, height: 14 }) : null,
9231
9297
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QualityBars, { quality: participant.quality })
@@ -9964,7 +10030,13 @@ function PeoplePanel({
9964
10030
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "mx-meet__person-name", children: [
9965
10031
  participant.displayName,
9966
10032
  participant.identity === local ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "mx-meet__you", children: " (you)" }) : null,
9967
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RoleBadge, { role: participant.identity === local ? myRole : participant.role }),
10033
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
10034
+ RoleBadge,
10035
+ {
10036
+ role: participant.identity === local ? myRole : participant.role,
10037
+ standing: participant.standing
10038
+ }
10039
+ ),
9968
10040
  isNoteTaker(participant) ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "mx-meet__badge", children: "Meeting assistant" }) : null,
9969
10041
  snapshot?.spotlight === participant.identity ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "mx-meet__badge", children: "Spotlight" }) : null
9970
10042
  ] }),
@@ -11126,7 +11198,7 @@ function MeetingRecordBody({
11126
11198
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "mx-meet__person-name", children: [
11127
11199
  displayNameFor(bundle.names, person.identity, person.displayName),
11128
11200
  person.role === "host" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "mx-meet__badge", children: "Host" }) : null,
11129
- person.role === "guest" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "mx-meet__badge", children: "Guest" }) : null,
11201
+ person.userId === null && !person.isAgent ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "mx-meet__badge", children: "Guest" }) : null,
11130
11202
  person.isAgent ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "mx-meet__badge", children: "Meeting assistant" }) : null
11131
11203
  ] })
11132
11204
  ] }, person.id)) })