@ai-matrx/meet 0.8.1 → 0.10.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/CHANGELOG.md CHANGED
@@ -1,5 +1,45 @@
1
1
  # Changelog — `@ai-matrx/meet`
2
2
 
3
+ ## 0.10.0
4
+ ### Unreleased
5
+ ### S4: admission truth — the wait reads the server
6
+
7
+ - **The waiting room reads `GET /v1/meet/state`** (`MEET_ROUTES.state`) on a timer
8
+ (`waiting_poll_seconds`), on every `mx.state.changed` hint, on `online` and on visibility
9
+ return. `snapshot.waiting` holds the row's word; `useWaiting()` exposes it with `withdraw()`
10
+ and `askAgain()`. New phases rendered: `waiting:host_not_started`, `denied`, `knock_expired`,
11
+ `left` (withdrawn); `data-meet-host-present` while waiting.
12
+ - **Admission RPCs** `meet_admit`, `meet_deny`, `meet_undeny`, `meet_admit_all` return rows
13
+ (`repository.decideAdmission`, `repository.admitAll`); `MeetingSession.undeny`.
14
+ - **A token that cannot subscribe never renders the in-call screen.**
15
+ - **Removed (no shim):** `MEET_EVENTS.knock`, `.admission`, `.lock`, `.recording`;
16
+ `MeetingSession.knock`, `useLobby().knock`, the `onDenied` option, `RPCS.admit =
17
+ meet_admit_participant` (dropped from the database). `MEET_EVENTS.stateChanged` is the one
18
+ room-channel event. `AdmissionState` widens to the server's eight states.
19
+
20
+ Consumer action: none for `<MeetingSkinRoot>` consumers; a custom waiting screen reads
21
+ `useWaiting()`.
22
+
23
+ ## 0.9.0
24
+ ### S3: the meeting pass, the role/standing vocabulary, refusal phases
25
+
26
+ - **The meeting pass.** `RoomToken` gains `meetingPass`, `meetingPassExpiresAt`, `sessionId`,
27
+ `standing`. Every aidream meet route (record, claim, chat, collab, moderate, Q&A, captions)
28
+ now reads `x-meet-pass` (`MEETING_PASS_HEADER`, `meetingPassHeaders`); the LiveKit `token` is
29
+ for media only. `ROOM_TOKEN_HEADER` is removed (no shim). `rememberedMeetingPass(room)` reads
30
+ a guest's kept pass.
31
+ - **Role vocabulary** `host · cohost · presenter · participant · viewer`; being a guest is the
32
+ STANDING `guest` (`ParticipantStanding`, `isLinkFollower`, attribute
33
+ `matrx.participant.standing`). `data-meet-role` still renders `guest` for a link follower.
34
+ - **Refusals are phases.** `MeetError.reason` carries the join gate's reason code; a refused
35
+ join renders `refused:<reason>` (`ended` renders the `ended` phase), never pre-join.
36
+ - **Session-aware record:** `loadGuestMeetingRecord({ sessionId })`.
37
+ - **Removed:** `RPCS.endMeeting` / `repository.endMeeting` (the `meet_end_meeting` RPC is
38
+ dropped; `/v1/meet/end` is the one end door).
39
+
40
+ Consumer action: send `meetingPass` (not `token`) as `x-meet-pass`; read the guest badge from
41
+ `standing`, not `role === "guest"`; replace `ROOM_TOKEN_HEADER` with `MEETING_PASS_HEADER`.
42
+
3
43
  ## 0.8.1
4
44
 
5
45
  Automatic changed-only republish (docs/metadata drift since the last tag — see
@@ -57,19 +57,23 @@ declare function isGuest(identity: MeetIdentity): boolean;
57
57
  /**
58
58
  * WHO SOMEBODY IS IN A ROOM — the SERVER's word, never this client's (MRI-A11).
59
59
  *
60
- * `host` is `meet_meetings.host_user_id` or a real `iam` grant on the meeting;
61
- * `participant` is an authenticated member of the meeting's organization;
62
- * `guest` is a link-follower with no session. Organization membership is
63
- * TENANCY and never permission, which is why "member of the org" lands on
64
- * `participant` and not on `host`.
65
- *
66
- * `cohost` has no server-side minter yet and is kept because the rank ladder
67
- * below is the thing that stops a co-host from removing the host; the moment a
68
- * co-host grant exists it slots in without a second vocabulary.
60
+ * THE ROLE VOCABULARY (CORE-DESIGN §2.1, S3): `host · cohost · presenter · participant ·
61
+ * viewer`. `host` is `meet_meetings.host_user_id`; `cohost` is a real `iam` grant on the
62
+ * meeting. Being a guest is a STANDING (`ParticipantStanding`), never a role: a guest is a
63
+ * `participant` whose standing is `guest`. Pinned against aidream's `config.py` by
64
+ * `test_meet_service.py`.
65
+ */
66
+ type ParticipantRole = "host" | "cohost" | "presenter" | "participant" | "viewer";
67
+ /**
68
+ * Where a person stands with the meeting, beside the role: `member` of its organization,
69
+ * `invited` (shared with them), `outsider` (signed in, followed the link), `guest` (no
70
+ * session). The server mints it (attribute `matrx.participant.standing`).
69
71
  */
70
- type ParticipantRole = "host" | "cohost" | "participant" | "guest";
72
+ type ParticipantStanding = "member" | "invited" | "outsider" | "guest";
71
73
  /** Rank, so "can this actor do that to that participant" is one comparison. */
72
74
  declare const ROLE_RANK: Readonly<Record<ParticipantRole, number>>;
75
+ /** Does this standing follow the link-holder (guest) rules? `outsider` and `guest`. */
76
+ declare function isLinkFollower(standing: ParticipantStanding | null | undefined): boolean;
73
77
  /**
74
78
  * 🚨 THE ONE PREDICATE FOR "DOES THIS PERSON HOLD HOST POWERS".
75
79
  *
@@ -83,7 +87,7 @@ declare function isHostRole(role: ParticipantRole): boolean;
83
87
  * admits or denies. An authenticated member of the meeting's org is `admitted`
84
88
  * on arrival unless the meeting is locked.
85
89
  */
86
- type AdmissionState = "knocking" | "admitted" | "denied" | "removed";
90
+ type AdmissionState = "waiting_host" | "knocking" | "admitted" | "denied" | "expired" | "withdrawn" | "removed" | "ended";
87
91
  interface LobbyEntry {
88
92
  readonly identity: ParticipantIdentity;
89
93
  readonly displayName: string;
@@ -91,6 +95,8 @@ interface LobbyEntry {
91
95
  readonly userId: UserId | null;
92
96
  readonly state: AdmissionState;
93
97
  readonly knockedAt: string;
98
+ /** When an unanswered knock lapses (`knock_timeout_minutes`); null = never. */
99
+ readonly knockExpiresAt?: string | null | undefined;
94
100
  readonly decidedAt: string | null;
95
101
  readonly decidedBy: UserId | null;
96
102
  }
@@ -102,6 +108,8 @@ interface MeetParticipant {
102
108
  readonly displayName: string;
103
109
  readonly avatarUrl: string | null;
104
110
  readonly role: ParticipantRole;
111
+ /** Where they stand with the meeting (server-minted); null when the server sent none. */
112
+ readonly standing?: ParticipantStanding | null;
105
113
  /**
106
114
  * Whether the SERVER granted this participant the power to start a recording
107
115
  * (MRI-A11). It is not `role === "host"`: a meeting whose recording policy is
@@ -367,6 +375,9 @@ interface MeetingAttendee {
367
375
  readonly userId: UserId | null;
368
376
  readonly role: ParticipantRole;
369
377
  readonly admissionState: AdmissionState;
378
+ /** When this person knocked, and when an unanswered knock lapses (null = never). */
379
+ readonly knockedAt?: string | null | undefined;
380
+ readonly knockExpiresAt?: string | null | undefined;
370
381
  readonly isAgent: boolean;
371
382
  /** FIRST arrival in the room — a rejoin never moves it. */
372
383
  readonly joinedAt: string | null;
@@ -800,6 +811,6 @@ interface MeetingActivities {
800
811
  * The same `GET /v1/meet/collab` the room reads on join; a refusal is returned as data,
801
812
  * so the record still renders everything else.
802
813
  */
803
- declare function loadMeetingActivities(api: MeetApi, meetingId: string, roomToken?: string | null): Promise<MeetingActivities>;
814
+ declare function loadMeetingActivities(api: MeetApi, meetingId: string, meetingPass?: string | null): Promise<MeetingActivities>;
804
815
 
805
- export { type NoteTakerState as $, type AccessTokenSource as A, type MeetPollState as B, type CollabPanel as C, type MeetQuestion as D, EMPTY_COLLAB as E, FILE_SESSION_PATH as F, type MeetQuestionState as G, type MeetStroke as H, type InviteeInput as I, type JsonObject as J, type MeetingActivities as K, type LobbyEntry as L, type MeetingRecord as M, type MeetingAttendee as N, type OrganizationId as O, type ParticipantIdentity as P, type MeetingChanges as Q, type RoomName as R, type StageLayout as S, type TranscriptSource as T, type UserId as U, type MeetingInvitee as V, type WrapUpAnnouncement as W, type MeetingKind as X, type MeetingNoteKind as Y, type MeetingOccurrence as Z, type MeetingSettings as _, type MeetParticipant as a, ORGANIZATION_HEADER as a0, type OccurrenceOverride as a1, type OccurrenceState as a2, ROLE_RANK as a3, type RecordingPolicy as a4, type RecordingRecord as a5, type RecordingState as a6, type RoomPhase as a7, type RsvpAnswer as a8, type RsvpInvitation as a9, type RsvpState as aa, type TranscriptSegment as ab, type UpcomingOccurrence as ac, applyCollabPacket as ad, asCallId as ae, asMeetingId as af, asOrganizationId as ag, asParticipantIdentity as ah, asRoomName as ai, asUserId as aj, assignedRoom as ak, autoAssign as al, breakoutRemainingMs as am, collabFromState as an, createMeetApi as ao, defaultCaptionLanguage as ap, fileDownloadPath as aq, isGuest as ar, isHostRole as as, loadMeetingActivities as at, withItem as au, type RecordingSource as av, type MeetApi as b, type MeetIdentity as c, type CallInvite as d, type ParticipantRole as e, type CallMode as f, type MeetingNote as g, type MeetingId as h, type CollabSnapshot as i, type AdmissionState as j, CAPTION_LANGUAGES as k, type CallId as l, type CallState as m, type CallablePerson as n, type ConnectionQuality as o, type InviteeRole as p, type JsonValue as q, type MeetApiOptions as r, type MeetApiRequest as s, type MeetBreakoutBroadcast as t, type MeetBreakoutPlan as u, type MeetBreakoutRoom as v, type MeetCollabSettings as w, type MeetFileMedia as x, type MeetPoll as y, type MeetPollOption as z };
816
+ export { type NoteTakerState as $, type AccessTokenSource as A, type MeetPollState as B, type CollabPanel as C, type MeetQuestion as D, EMPTY_COLLAB as E, FILE_SESSION_PATH as F, type MeetQuestionState as G, type MeetStroke as H, type InviteeInput as I, type JsonObject as J, type MeetingActivities as K, type LobbyEntry as L, type MeetingRecord as M, type MeetingAttendee as N, type OrganizationId as O, type ParticipantIdentity as P, type MeetingChanges as Q, type RoomName as R, type StageLayout as S, type TranscriptSource as T, type UserId as U, type MeetingInvitee as V, type WrapUpAnnouncement as W, type MeetingKind as X, type MeetingNoteKind as Y, type MeetingOccurrence as Z, type MeetingSettings as _, type MeetParticipant as a, ORGANIZATION_HEADER as a0, type OccurrenceOverride as a1, type OccurrenceState as a2, type ParticipantStanding as a3, ROLE_RANK as a4, type RecordingPolicy as a5, type RecordingRecord as a6, type RecordingState as a7, type RoomPhase as a8, type RsvpAnswer as a9, type RsvpInvitation as aa, type RsvpState as ab, type TranscriptSegment as ac, type UpcomingOccurrence as ad, applyCollabPacket as ae, asCallId as af, asMeetingId as ag, asOrganizationId as ah, asParticipantIdentity as ai, asRoomName as aj, asUserId as ak, assignedRoom as al, autoAssign as am, breakoutRemainingMs as an, collabFromState as ao, createMeetApi as ap, defaultCaptionLanguage as aq, fileDownloadPath as ar, isGuest as as, isHostRole as at, isLinkFollower as au, loadMeetingActivities as av, withItem as aw, type RecordingSource as ax, type MeetApi as b, type MeetIdentity as c, type CallInvite as d, type ParticipantRole as e, type CallMode as f, type MeetingNote as g, type MeetingId as h, type CollabSnapshot as i, type AdmissionState as j, CAPTION_LANGUAGES as k, type CallId as l, type CallState as m, type CallablePerson as n, type ConnectionQuality as o, type InviteeRole as p, type JsonValue as q, type MeetApiOptions as r, type MeetApiRequest as s, type MeetBreakoutBroadcast as t, type MeetBreakoutPlan as u, type MeetBreakoutRoom as v, type MeetCollabSettings as w, type MeetFileMedia as x, type MeetPoll as y, type MeetPollOption as z };
@@ -57,19 +57,23 @@ declare function isGuest(identity: MeetIdentity): boolean;
57
57
  /**
58
58
  * WHO SOMEBODY IS IN A ROOM — the SERVER's word, never this client's (MRI-A11).
59
59
  *
60
- * `host` is `meet_meetings.host_user_id` or a real `iam` grant on the meeting;
61
- * `participant` is an authenticated member of the meeting's organization;
62
- * `guest` is a link-follower with no session. Organization membership is
63
- * TENANCY and never permission, which is why "member of the org" lands on
64
- * `participant` and not on `host`.
65
- *
66
- * `cohost` has no server-side minter yet and is kept because the rank ladder
67
- * below is the thing that stops a co-host from removing the host; the moment a
68
- * co-host grant exists it slots in without a second vocabulary.
60
+ * THE ROLE VOCABULARY (CORE-DESIGN §2.1, S3): `host · cohost · presenter · participant ·
61
+ * viewer`. `host` is `meet_meetings.host_user_id`; `cohost` is a real `iam` grant on the
62
+ * meeting. Being a guest is a STANDING (`ParticipantStanding`), never a role: a guest is a
63
+ * `participant` whose standing is `guest`. Pinned against aidream's `config.py` by
64
+ * `test_meet_service.py`.
65
+ */
66
+ type ParticipantRole = "host" | "cohost" | "presenter" | "participant" | "viewer";
67
+ /**
68
+ * Where a person stands with the meeting, beside the role: `member` of its organization,
69
+ * `invited` (shared with them), `outsider` (signed in, followed the link), `guest` (no
70
+ * session). The server mints it (attribute `matrx.participant.standing`).
69
71
  */
70
- type ParticipantRole = "host" | "cohost" | "participant" | "guest";
72
+ type ParticipantStanding = "member" | "invited" | "outsider" | "guest";
71
73
  /** Rank, so "can this actor do that to that participant" is one comparison. */
72
74
  declare const ROLE_RANK: Readonly<Record<ParticipantRole, number>>;
75
+ /** Does this standing follow the link-holder (guest) rules? `outsider` and `guest`. */
76
+ declare function isLinkFollower(standing: ParticipantStanding | null | undefined): boolean;
73
77
  /**
74
78
  * 🚨 THE ONE PREDICATE FOR "DOES THIS PERSON HOLD HOST POWERS".
75
79
  *
@@ -83,7 +87,7 @@ declare function isHostRole(role: ParticipantRole): boolean;
83
87
  * admits or denies. An authenticated member of the meeting's org is `admitted`
84
88
  * on arrival unless the meeting is locked.
85
89
  */
86
- type AdmissionState = "knocking" | "admitted" | "denied" | "removed";
90
+ type AdmissionState = "waiting_host" | "knocking" | "admitted" | "denied" | "expired" | "withdrawn" | "removed" | "ended";
87
91
  interface LobbyEntry {
88
92
  readonly identity: ParticipantIdentity;
89
93
  readonly displayName: string;
@@ -91,6 +95,8 @@ interface LobbyEntry {
91
95
  readonly userId: UserId | null;
92
96
  readonly state: AdmissionState;
93
97
  readonly knockedAt: string;
98
+ /** When an unanswered knock lapses (`knock_timeout_minutes`); null = never. */
99
+ readonly knockExpiresAt?: string | null | undefined;
94
100
  readonly decidedAt: string | null;
95
101
  readonly decidedBy: UserId | null;
96
102
  }
@@ -102,6 +108,8 @@ interface MeetParticipant {
102
108
  readonly displayName: string;
103
109
  readonly avatarUrl: string | null;
104
110
  readonly role: ParticipantRole;
111
+ /** Where they stand with the meeting (server-minted); null when the server sent none. */
112
+ readonly standing?: ParticipantStanding | null;
105
113
  /**
106
114
  * Whether the SERVER granted this participant the power to start a recording
107
115
  * (MRI-A11). It is not `role === "host"`: a meeting whose recording policy is
@@ -367,6 +375,9 @@ interface MeetingAttendee {
367
375
  readonly userId: UserId | null;
368
376
  readonly role: ParticipantRole;
369
377
  readonly admissionState: AdmissionState;
378
+ /** When this person knocked, and when an unanswered knock lapses (null = never). */
379
+ readonly knockedAt?: string | null | undefined;
380
+ readonly knockExpiresAt?: string | null | undefined;
370
381
  readonly isAgent: boolean;
371
382
  /** FIRST arrival in the room — a rejoin never moves it. */
372
383
  readonly joinedAt: string | null;
@@ -800,6 +811,6 @@ interface MeetingActivities {
800
811
  * The same `GET /v1/meet/collab` the room reads on join; a refusal is returned as data,
801
812
  * so the record still renders everything else.
802
813
  */
803
- declare function loadMeetingActivities(api: MeetApi, meetingId: string, roomToken?: string | null): Promise<MeetingActivities>;
814
+ declare function loadMeetingActivities(api: MeetApi, meetingId: string, meetingPass?: string | null): Promise<MeetingActivities>;
804
815
 
805
- export { type NoteTakerState as $, type AccessTokenSource as A, type MeetPollState as B, type CollabPanel as C, type MeetQuestion as D, EMPTY_COLLAB as E, FILE_SESSION_PATH as F, type MeetQuestionState as G, type MeetStroke as H, type InviteeInput as I, type JsonObject as J, type MeetingActivities as K, type LobbyEntry as L, type MeetingRecord as M, type MeetingAttendee as N, type OrganizationId as O, type ParticipantIdentity as P, type MeetingChanges as Q, type RoomName as R, type StageLayout as S, type TranscriptSource as T, type UserId as U, type MeetingInvitee as V, type WrapUpAnnouncement as W, type MeetingKind as X, type MeetingNoteKind as Y, type MeetingOccurrence as Z, type MeetingSettings as _, type MeetParticipant as a, ORGANIZATION_HEADER as a0, type OccurrenceOverride as a1, type OccurrenceState as a2, ROLE_RANK as a3, type RecordingPolicy as a4, type RecordingRecord as a5, type RecordingState as a6, type RoomPhase as a7, type RsvpAnswer as a8, type RsvpInvitation as a9, type RsvpState as aa, type TranscriptSegment as ab, type UpcomingOccurrence as ac, applyCollabPacket as ad, asCallId as ae, asMeetingId as af, asOrganizationId as ag, asParticipantIdentity as ah, asRoomName as ai, asUserId as aj, assignedRoom as ak, autoAssign as al, breakoutRemainingMs as am, collabFromState as an, createMeetApi as ao, defaultCaptionLanguage as ap, fileDownloadPath as aq, isGuest as ar, isHostRole as as, loadMeetingActivities as at, withItem as au, type RecordingSource as av, type MeetApi as b, type MeetIdentity as c, type CallInvite as d, type ParticipantRole as e, type CallMode as f, type MeetingNote as g, type MeetingId as h, type CollabSnapshot as i, type AdmissionState as j, CAPTION_LANGUAGES as k, type CallId as l, type CallState as m, type CallablePerson as n, type ConnectionQuality as o, type InviteeRole as p, type JsonValue as q, type MeetApiOptions as r, type MeetApiRequest as s, type MeetBreakoutBroadcast as t, type MeetBreakoutPlan as u, type MeetBreakoutRoom as v, type MeetCollabSettings as w, type MeetFileMedia as x, type MeetPoll as y, type MeetPollOption as z };
816
+ export { type NoteTakerState as $, type AccessTokenSource as A, type MeetPollState as B, type CollabPanel as C, type MeetQuestion as D, EMPTY_COLLAB as E, FILE_SESSION_PATH as F, type MeetQuestionState as G, type MeetStroke as H, type InviteeInput as I, type JsonObject as J, type MeetingActivities as K, type LobbyEntry as L, type MeetingRecord as M, type MeetingAttendee as N, type OrganizationId as O, type ParticipantIdentity as P, type MeetingChanges as Q, type RoomName as R, type StageLayout as S, type TranscriptSource as T, type UserId as U, type MeetingInvitee as V, type WrapUpAnnouncement as W, type MeetingKind as X, type MeetingNoteKind as Y, type MeetingOccurrence as Z, type MeetingSettings as _, type MeetParticipant as a, ORGANIZATION_HEADER as a0, type OccurrenceOverride as a1, type OccurrenceState as a2, type ParticipantStanding as a3, ROLE_RANK as a4, type RecordingPolicy as a5, type RecordingRecord as a6, type RecordingState as a7, type RoomPhase as a8, type RsvpAnswer as a9, type RsvpInvitation as aa, type RsvpState as ab, type TranscriptSegment as ac, type UpcomingOccurrence as ad, applyCollabPacket as ae, asCallId as af, asMeetingId as ag, asOrganizationId as ah, asParticipantIdentity as ai, asRoomName as aj, asUserId as ak, assignedRoom as al, autoAssign as am, breakoutRemainingMs as an, collabFromState as ao, createMeetApi as ap, defaultCaptionLanguage as aq, fileDownloadPath as ar, isGuest as as, isHostRole as at, isLinkFollower as au, loadMeetingActivities as av, withItem as aw, type RecordingSource as ax, type MeetApi as b, type MeetIdentity as c, type CallInvite as d, type ParticipantRole as e, type CallMode as f, type MeetingNote as g, type MeetingId as h, type CollabSnapshot as i, type AdmissionState as j, CAPTION_LANGUAGES as k, type CallId as l, type CallState as m, type CallablePerson as n, type ConnectionQuality as o, type InviteeRole as p, type JsonValue as q, type MeetApiOptions as r, type MeetApiRequest as s, type MeetBreakoutBroadcast as t, type MeetBreakoutPlan as u, type MeetBreakoutRoom as v, type MeetCollabSettings as w, type MeetFileMedia as x, type MeetPoll as y, type MeetPollOption as z };
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
- import { M as MeetingRecord, P as ParticipantIdentity, R as RoomName, a as MeetParticipant } from './collab-Bss-_Jfp.js';
2
+ import { M as MeetingRecord, P as ParticipantIdentity, R as RoomName, a as MeetParticipant } from './collab-C2R-kQnV.js';
3
3
 
4
4
  /**
5
5
  * THE PRODUCT UI (R6/R7). Not a headless kernel with a note telling the host to
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
- import { M as MeetingRecord, P as ParticipantIdentity, R as RoomName, a as MeetParticipant } from './collab-Bss-_Jfp.cjs';
2
+ import { M as MeetingRecord, P as ParticipantIdentity, R as RoomName, a as MeetParticipant } from './collab-C2R-kQnV.cjs';
3
3
 
4
4
  /**
5
5
  * THE PRODUCT UI (R6/R7). Not a headless kernel with a note telling the host to