@ai-matrx/meet 0.9.0 → 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/dist/core.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as ParticipantIdentity, $ as NoteTakerState, a as MeetParticipant, M as MeetingRecord, a8 as RoomPhase, e as ParticipantRole, a3 as ParticipantStanding, S as StageLayout, L as LobbyEntry, a7 as RecordingState, U as UserId, ax as RecordingSource, ac as TranscriptSegment, g as MeetingNote, W as WrapUpAnnouncement, i as CollabSnapshot, o as ConnectionQuality, j as AdmissionState, h as MeetingId, R as RoomName, b as MeetApi, d as CallInvite, f as CallMode, O as OrganizationId, l as CallId, m as CallState, X as MeetingKind, a5 as RecordingPolicy, a6 as RecordingRecord, N as MeetingAttendee, _ as MeetingSettings, Q as MeetingChanges, a1 as OccurrenceOverride, Z as MeetingOccurrence, ad as UpcomingOccurrence, V as MeetingInvitee, I as InviteeInput, p as InviteeRole, a9 as RsvpAnswer, aa as RsvpInvitation, c as MeetIdentity, C as CollabPanel } from './collab-B6scmSST.cjs';
2
- export { A as AccessTokenSource, k as CAPTION_LANGUAGES, n as CallablePerson, E as EMPTY_COLLAB, F as FILE_SESSION_PATH, J as JsonObject, q as JsonValue, r as MeetApiOptions, s as MeetApiRequest, t as MeetBreakoutBroadcast, u as MeetBreakoutPlan, v as MeetBreakoutRoom, w as MeetCollabSettings, x as MeetFileMedia, y as MeetPoll, z as MeetPollOption, B as MeetPollState, D as MeetQuestion, G as MeetQuestionState, H as MeetStroke, K as MeetingActivities, Y as MeetingNoteKind, a0 as ORGANIZATION_HEADER, a2 as OccurrenceState, a4 as ROLE_RANK, ab as RsvpState, T as TranscriptSource, ae as applyCollabPacket, af as asCallId, ag as asMeetingId, ah as asOrganizationId, ai as asParticipantIdentity, aj as asRoomName, ak as asUserId, al as assignedRoom, am as autoAssign, an as breakoutRemainingMs, ao as collabFromState, ap as createMeetApi, aq as defaultCaptionLanguage, ar as fileDownloadPath, as as isGuest, at as isHostRole, au as isLinkFollower, av as loadMeetingActivities, aw as withItem } from './collab-B6scmSST.cjs';
1
+ import { P as ParticipantIdentity, $ as NoteTakerState, a as MeetParticipant, M as MeetingRecord, a8 as RoomPhase, j as AdmissionState, e as ParticipantRole, a3 as ParticipantStanding, S as StageLayout, L as LobbyEntry, a7 as RecordingState, U as UserId, ax as RecordingSource, ac as TranscriptSegment, g as MeetingNote, W as WrapUpAnnouncement, i as CollabSnapshot, o as ConnectionQuality, h as MeetingId, R as RoomName, b as MeetApi, d as CallInvite, f as CallMode, O as OrganizationId, l as CallId, m as CallState, X as MeetingKind, a5 as RecordingPolicy, N as MeetingAttendee, a6 as RecordingRecord, _ as MeetingSettings, Q as MeetingChanges, a1 as OccurrenceOverride, Z as MeetingOccurrence, ad as UpcomingOccurrence, V as MeetingInvitee, I as InviteeInput, p as InviteeRole, a9 as RsvpAnswer, aa as RsvpInvitation, c as MeetIdentity, C as CollabPanel } from './collab-C2R-kQnV.cjs';
2
+ export { A as AccessTokenSource, k as CAPTION_LANGUAGES, n as CallablePerson, E as EMPTY_COLLAB, F as FILE_SESSION_PATH, J as JsonObject, q as JsonValue, r as MeetApiOptions, s as MeetApiRequest, t as MeetBreakoutBroadcast, u as MeetBreakoutPlan, v as MeetBreakoutRoom, w as MeetCollabSettings, x as MeetFileMedia, y as MeetPoll, z as MeetPollOption, B as MeetPollState, D as MeetQuestion, G as MeetQuestionState, H as MeetStroke, K as MeetingActivities, Y as MeetingNoteKind, a0 as ORGANIZATION_HEADER, a2 as OccurrenceState, a4 as ROLE_RANK, ab as RsvpState, T as TranscriptSource, ae as applyCollabPacket, af as asCallId, ag as asMeetingId, ah as asOrganizationId, ai as asParticipantIdentity, aj as asRoomName, ak as asUserId, al as assignedRoom, am as autoAssign, an as breakoutRemainingMs, ao as collabFromState, ap as createMeetApi, aq as defaultCaptionLanguage, ar as fileDownloadPath, as as isGuest, at as isHostRole, au as isLinkFollower, av as loadMeetingActivities, aw as withItem } from './collab-C2R-kQnV.cjs';
3
3
  import { RealtimeManager } from '@ai-matrx/realtime';
4
4
  import { MessagingSupabaseClient, ActionHandler } from '@ai-matrx/messaging';
5
5
  import { RoomOptions, ConnectionQuality as ConnectionQuality$1, Participant } from 'livekit-client';
@@ -344,8 +344,28 @@ interface MeetGrants {
344
344
  }
345
345
  /** No token yet grants nothing. Never "assume host until told otherwise". */
346
346
  declare const NO_GRANTS: MeetGrants;
347
+ /**
348
+ * S4 — THIS PERSON'S WAIT, as the server's state read (`GET /v1/meet/state`) last said it
349
+ * (CORE-DESIGN §2.6). Set while `phase === "lobby"`; the waiting screens read it, never a
350
+ * broadcast. `admission` is the row's own word: `waiting_host` · `knocking` · `denied` ·
351
+ * `expired` · `withdrawn` · `ended` (`admitted` is never held here — it is a join).
352
+ */
353
+ interface MeetWaiting {
354
+ readonly admission: AdmissionState;
355
+ /** Is anyone who may admit in the room? null until the first read. */
356
+ readonly admittersPresent: boolean | null;
357
+ /** May a denied person ask again (`reknock_after_deny`)? */
358
+ readonly reknockAllowed: boolean;
359
+ readonly knockExpiresAt: string | null;
360
+ /** How often the core reads while waiting (`waiting_poll_seconds`). */
361
+ readonly pollSeconds: number;
362
+ /** The run's `live_version` at the last read. */
363
+ readonly liveVersion: number;
364
+ }
347
365
  interface MeetSnapshot {
348
366
  readonly phase: RoomPhase;
367
+ /** S4: this person's wait (see `MeetWaiting`); null outside the waiting room. */
368
+ readonly waiting: MeetWaiting | null;
349
369
  readonly meeting: MeetingRecord | null;
350
370
  readonly localIdentity: ParticipantIdentity | null;
351
371
  /** The server's word on what THIS joiner may do. See `MeetGrants`. */
@@ -743,7 +763,10 @@ declare const RPCS: {
743
763
  readonly getOrCreateMeeting: "meet_get_or_create_meeting";
744
764
  /** Resolve a durable public link, before/during/after its scheduled time. */
745
765
  readonly meetingBySlug: "meet_meeting_by_slug";
746
- readonly admit: "meet_admit_participant";
766
+ readonly admit: "meet_admit";
767
+ readonly deny: "meet_deny";
768
+ readonly undeny: "meet_undeny";
769
+ readonly admitAll: "meet_admit_all";
747
770
  readonly setLock: "meet_set_lock";
748
771
  readonly recordConsent: "meet_record_consent";
749
772
  /** Schedule with every setting at create; unset settings come from the knobs. */
@@ -827,12 +850,15 @@ interface MeetRepository {
827
850
  readonly items: readonly MeetingRecord[];
828
851
  readonly hasMore: boolean;
829
852
  }>;
830
- admit(args: {
853
+ /** S4: one decision on one waiting person; returns the row as it now stands. */
854
+ decideAdmission(args: {
831
855
  meetingId: MeetingId;
832
856
  identity: string;
833
- admitted: boolean;
857
+ decision: "admit" | "deny" | "undeny";
834
858
  byUserId: UserId;
835
- }): Promise<void>;
859
+ }): Promise<MeetingAttendee>;
860
+ /** S4: admit everyone still waiting (not expired); returns the admitted rows. */
861
+ admitAll(meetingId: MeetingId, byUserId: UserId): Promise<readonly MeetingAttendee[]>;
836
862
  setLock(meetingId: MeetingId, locked: boolean, byUserId: UserId): Promise<MeetingRecord>;
837
863
  projectSegment(row: Row): TranscriptSegment;
838
864
  projectNote(row: Row): MeetingNote;
@@ -1121,14 +1147,15 @@ declare const MEET_EVENTS: {
1121
1147
  readonly cancel: "mx.call.cancel";
1122
1148
  /** You answered (or declined) on another device. Stop ringing here. */
1123
1149
  readonly settled: "mx.call.settled";
1124
- /** Someone is in the lobby. Hosts render the knock. */
1125
- readonly knock: "mx.lobby.knock";
1126
- /** A host decided. The knocker learns it here — they have no DB read. */
1127
- readonly admission: "mx.lobby.admission";
1128
- /** The room was locked or unlocked. */
1129
- readonly lock: "mx.room.lock";
1130
- /** Recording started or stopped. EVERY participant renders the indicator. */
1131
- readonly recording: "mx.room.recording";
1150
+ /**
1151
+ * 🚨 S4 (CORE-DESIGN §2.6): the ONE room-channel event — payload-free "something changed,
1152
+ * read again". Nothing a person must see rides it: a waiting person learns admitted /
1153
+ * denied / expired / ended by READING their row (`GET /v1/meet/state`) on a timer and on
1154
+ * every hint. The four payload broadcasts (`mx.lobby.knock`, `mx.lobby.admission`,
1155
+ * `mx.room.lock`, `mx.room.recording`) are gone with their senders and receivers. The
1156
+ * server publishes the same event on the same topic (aidream `admission.room_topic`).
1157
+ */
1158
+ readonly stateChanged: "mx.state.changed";
1132
1159
  };
1133
1160
  /**
1134
1161
  * 🚨 `mx.meeting.transcript` and `mx.meeting.note` WERE declared here and
@@ -1766,14 +1793,12 @@ interface MeetingSessionOptions {
1766
1793
  */
1767
1794
  onAdmitted?: (() => void) | undefined;
1768
1795
  /**
1769
- * 🚨 THE HOST DENIED *US*. Called once per denial verdict that names this
1770
- * knocker. Without it the waiting room kept promising "you will join
1771
- * automatically" to a person the host had already turned away (production
1772
- * 2026-09-27). The provider wires it to `engine.rejoin()`: the server then
1773
- * refuses the mint with its own sentence ("The host did not admit you…"),
1774
- * so the words on screen are the server's decision, never the client's guess.
1796
+ * S4: the meeting pass this device holds (`x-meet-pass`) — what the state read and
1797
+ * `/leave` are authorized by. Null when no pass is held yet.
1775
1798
  */
1776
- onDenied?: (() => void) | undefined;
1799
+ resolvePass?: (() => string | null) | undefined;
1800
+ /** S4: mint again (Ask to join again / Rejoin from the waiting screens). */
1801
+ rejoin?: (() => Promise<void>) | undefined;
1777
1802
  }
1778
1803
  interface MeetingSession {
1779
1804
  /** Subscribe to the room's out-of-band plane. Hosts see knocks; guests see verdicts. */
@@ -1786,10 +1811,24 @@ interface MeetingSession {
1786
1811
  * permanently missing the minute nobody noticed.
1787
1812
  */
1788
1813
  watchMeeting(meetingId: MeetingId): void;
1789
- /** A guest (or a late arrival at a locked room) announces themselves. */
1790
- knock(roomName: RoomName): void;
1791
1814
  admit(entry: LobbyEntry, admitted: boolean): Promise<void>;
1815
+ /** S4: lift a denial so the person may knock again (`meet_undeny`). */
1816
+ undeny(entry: LobbyEntry): Promise<void>;
1792
1817
  admitAll(): Promise<void>;
1818
+ /**
1819
+ * 🚨 S4 — THE WAIT READS SERVER TRUTH (CORE-DESIGN §2.6). While this tab waits, the state
1820
+ * read (`GET /v1/meet/state`) runs every `waiting_poll_seconds`, on every
1821
+ * `mx.state.changed` hint, on `online` and on visibility return. Admitted → a fresh mint
1822
+ * (`rejoin`); denied / expired / ended are what the row says, never a broadcast's guess.
1823
+ */
1824
+ startWaiting(): void;
1825
+ stopWaiting(): void;
1826
+ /** One state read now (idempotent while one is in flight). */
1827
+ readState(): Promise<void>;
1828
+ /** Stop waiting: the row becomes `withdrawn` (`POST /v1/meet/leave {intent: "withdraw"}`). */
1829
+ withdraw(): Promise<void>;
1830
+ /** Ask again after a denial or an expired knock (only offered when allowed). */
1831
+ askAgain(): Promise<void>;
1793
1832
  setLock(locked: boolean): Promise<MeetingRecord>;
1794
1833
  /** End it for everyone, through the server (MRI-A6). */
1795
1834
  endForEveryone(): Promise<EndMeetingResult>;
@@ -1925,6 +1964,12 @@ interface RoomToken {
1925
1964
  readonly sessionId: string | null;
1926
1965
  /** True when the server put this joiner in the lobby (D6). */
1927
1966
  readonly lobby: boolean;
1967
+ /**
1968
+ * S4: what the mint wrote on the person row — `admitted` · `knocking` · `waiting_host`.
1969
+ * A waiting person then reads `GET /v1/meet/state` every `pollSeconds`.
1970
+ */
1971
+ readonly admissionState?: AdmissionState | undefined;
1972
+ readonly pollSeconds?: number | undefined;
1928
1973
  /**
1929
1974
  * Meet wave 5: the breakout room this pass is for, or null for the main room. The
1930
1975
  * pass is still keyed by the MEETING's room name — it is this person's pass for the
@@ -2070,6 +2115,16 @@ declare const MEET_ROUTES: {
2070
2115
  readonly collab: "/api/v1/meet/collab";
2071
2116
  /** Meet wave 5: translate finished caption lines into this viewer's language. */
2072
2117
  readonly captionsTranslate: "/api/v1/meet/captions/translate";
2118
+ /**
2119
+ * S4 — THE STATE READ (CORE-DESIGN §2.6): `GET ?meeting_id=` with `x-meet-pass`. This
2120
+ * person's admission (lazy expiry applied), whether anyone who can admit is here, the run's
2121
+ * phase. Read every `waiting_poll_seconds` while waiting and on every `mx.state.changed`.
2122
+ */
2123
+ readonly state: "/api/v1/meet/state";
2124
+ /** S4: `withdraw` (stop waiting) or `leave` (close this tab); the pass may ride in the body. */
2125
+ readonly leave: "/api/v1/meet/leave";
2126
+ /** S4: a pass holder (guests included) saw the recording notice, for this run. */
2127
+ readonly consent: "/api/v1/meet/consent";
2073
2128
  };
2074
2129
  /** A `MEET_ROUTES` template with its `{meeting_id}` filled in, URL-encoded. */
2075
2130
  declare function meetingPath(template: string, meetingId: string): string;
@@ -3039,7 +3094,7 @@ declare function takeMoveRequest(store: CollabStoreLike): {
3039
3094
  */
3040
3095
  type ObservedRole = "host" | "cohost" | "participant" | "guest";
3041
3096
  /** `data-meet-phase` values this release renders (a subset of the contract's §2). */
3042
- type ObservedPhase = "resolving" | `refused:${string}` | "prejoin" | "joining" | "waiting:knocking" | "in_call" | "disconnected" | "ended";
3097
+ type ObservedPhase = "resolving" | `refused:${string}` | "prejoin" | "joining" | "waiting:knocking" | "waiting:host_not_started" | "denied" | "knock_expired" | "left" | "in_call" | "disconnected" | "ended";
3043
3098
  type ObservedConnection = "stable" | "reconnecting" | "server_unreachable";
3044
3099
  interface MeetObservation {
3045
3100
  readonly phase: ObservedPhase;
package/dist/core.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as ParticipantIdentity, $ as NoteTakerState, a as MeetParticipant, M as MeetingRecord, a8 as RoomPhase, e as ParticipantRole, a3 as ParticipantStanding, S as StageLayout, L as LobbyEntry, a7 as RecordingState, U as UserId, ax as RecordingSource, ac as TranscriptSegment, g as MeetingNote, W as WrapUpAnnouncement, i as CollabSnapshot, o as ConnectionQuality, j as AdmissionState, h as MeetingId, R as RoomName, b as MeetApi, d as CallInvite, f as CallMode, O as OrganizationId, l as CallId, m as CallState, X as MeetingKind, a5 as RecordingPolicy, a6 as RecordingRecord, N as MeetingAttendee, _ as MeetingSettings, Q as MeetingChanges, a1 as OccurrenceOverride, Z as MeetingOccurrence, ad as UpcomingOccurrence, V as MeetingInvitee, I as InviteeInput, p as InviteeRole, a9 as RsvpAnswer, aa as RsvpInvitation, c as MeetIdentity, C as CollabPanel } from './collab-B6scmSST.js';
2
- export { A as AccessTokenSource, k as CAPTION_LANGUAGES, n as CallablePerson, E as EMPTY_COLLAB, F as FILE_SESSION_PATH, J as JsonObject, q as JsonValue, r as MeetApiOptions, s as MeetApiRequest, t as MeetBreakoutBroadcast, u as MeetBreakoutPlan, v as MeetBreakoutRoom, w as MeetCollabSettings, x as MeetFileMedia, y as MeetPoll, z as MeetPollOption, B as MeetPollState, D as MeetQuestion, G as MeetQuestionState, H as MeetStroke, K as MeetingActivities, Y as MeetingNoteKind, a0 as ORGANIZATION_HEADER, a2 as OccurrenceState, a4 as ROLE_RANK, ab as RsvpState, T as TranscriptSource, ae as applyCollabPacket, af as asCallId, ag as asMeetingId, ah as asOrganizationId, ai as asParticipantIdentity, aj as asRoomName, ak as asUserId, al as assignedRoom, am as autoAssign, an as breakoutRemainingMs, ao as collabFromState, ap as createMeetApi, aq as defaultCaptionLanguage, ar as fileDownloadPath, as as isGuest, at as isHostRole, au as isLinkFollower, av as loadMeetingActivities, aw as withItem } from './collab-B6scmSST.js';
1
+ import { P as ParticipantIdentity, $ as NoteTakerState, a as MeetParticipant, M as MeetingRecord, a8 as RoomPhase, j as AdmissionState, e as ParticipantRole, a3 as ParticipantStanding, S as StageLayout, L as LobbyEntry, a7 as RecordingState, U as UserId, ax as RecordingSource, ac as TranscriptSegment, g as MeetingNote, W as WrapUpAnnouncement, i as CollabSnapshot, o as ConnectionQuality, h as MeetingId, R as RoomName, b as MeetApi, d as CallInvite, f as CallMode, O as OrganizationId, l as CallId, m as CallState, X as MeetingKind, a5 as RecordingPolicy, N as MeetingAttendee, a6 as RecordingRecord, _ as MeetingSettings, Q as MeetingChanges, a1 as OccurrenceOverride, Z as MeetingOccurrence, ad as UpcomingOccurrence, V as MeetingInvitee, I as InviteeInput, p as InviteeRole, a9 as RsvpAnswer, aa as RsvpInvitation, c as MeetIdentity, C as CollabPanel } from './collab-C2R-kQnV.js';
2
+ export { A as AccessTokenSource, k as CAPTION_LANGUAGES, n as CallablePerson, E as EMPTY_COLLAB, F as FILE_SESSION_PATH, J as JsonObject, q as JsonValue, r as MeetApiOptions, s as MeetApiRequest, t as MeetBreakoutBroadcast, u as MeetBreakoutPlan, v as MeetBreakoutRoom, w as MeetCollabSettings, x as MeetFileMedia, y as MeetPoll, z as MeetPollOption, B as MeetPollState, D as MeetQuestion, G as MeetQuestionState, H as MeetStroke, K as MeetingActivities, Y as MeetingNoteKind, a0 as ORGANIZATION_HEADER, a2 as OccurrenceState, a4 as ROLE_RANK, ab as RsvpState, T as TranscriptSource, ae as applyCollabPacket, af as asCallId, ag as asMeetingId, ah as asOrganizationId, ai as asParticipantIdentity, aj as asRoomName, ak as asUserId, al as assignedRoom, am as autoAssign, an as breakoutRemainingMs, ao as collabFromState, ap as createMeetApi, aq as defaultCaptionLanguage, ar as fileDownloadPath, as as isGuest, at as isHostRole, au as isLinkFollower, av as loadMeetingActivities, aw as withItem } from './collab-C2R-kQnV.js';
3
3
  import { RealtimeManager } from '@ai-matrx/realtime';
4
4
  import { MessagingSupabaseClient, ActionHandler } from '@ai-matrx/messaging';
5
5
  import { RoomOptions, ConnectionQuality as ConnectionQuality$1, Participant } from 'livekit-client';
@@ -344,8 +344,28 @@ interface MeetGrants {
344
344
  }
345
345
  /** No token yet grants nothing. Never "assume host until told otherwise". */
346
346
  declare const NO_GRANTS: MeetGrants;
347
+ /**
348
+ * S4 — THIS PERSON'S WAIT, as the server's state read (`GET /v1/meet/state`) last said it
349
+ * (CORE-DESIGN §2.6). Set while `phase === "lobby"`; the waiting screens read it, never a
350
+ * broadcast. `admission` is the row's own word: `waiting_host` · `knocking` · `denied` ·
351
+ * `expired` · `withdrawn` · `ended` (`admitted` is never held here — it is a join).
352
+ */
353
+ interface MeetWaiting {
354
+ readonly admission: AdmissionState;
355
+ /** Is anyone who may admit in the room? null until the first read. */
356
+ readonly admittersPresent: boolean | null;
357
+ /** May a denied person ask again (`reknock_after_deny`)? */
358
+ readonly reknockAllowed: boolean;
359
+ readonly knockExpiresAt: string | null;
360
+ /** How often the core reads while waiting (`waiting_poll_seconds`). */
361
+ readonly pollSeconds: number;
362
+ /** The run's `live_version` at the last read. */
363
+ readonly liveVersion: number;
364
+ }
347
365
  interface MeetSnapshot {
348
366
  readonly phase: RoomPhase;
367
+ /** S4: this person's wait (see `MeetWaiting`); null outside the waiting room. */
368
+ readonly waiting: MeetWaiting | null;
349
369
  readonly meeting: MeetingRecord | null;
350
370
  readonly localIdentity: ParticipantIdentity | null;
351
371
  /** The server's word on what THIS joiner may do. See `MeetGrants`. */
@@ -743,7 +763,10 @@ declare const RPCS: {
743
763
  readonly getOrCreateMeeting: "meet_get_or_create_meeting";
744
764
  /** Resolve a durable public link, before/during/after its scheduled time. */
745
765
  readonly meetingBySlug: "meet_meeting_by_slug";
746
- readonly admit: "meet_admit_participant";
766
+ readonly admit: "meet_admit";
767
+ readonly deny: "meet_deny";
768
+ readonly undeny: "meet_undeny";
769
+ readonly admitAll: "meet_admit_all";
747
770
  readonly setLock: "meet_set_lock";
748
771
  readonly recordConsent: "meet_record_consent";
749
772
  /** Schedule with every setting at create; unset settings come from the knobs. */
@@ -827,12 +850,15 @@ interface MeetRepository {
827
850
  readonly items: readonly MeetingRecord[];
828
851
  readonly hasMore: boolean;
829
852
  }>;
830
- admit(args: {
853
+ /** S4: one decision on one waiting person; returns the row as it now stands. */
854
+ decideAdmission(args: {
831
855
  meetingId: MeetingId;
832
856
  identity: string;
833
- admitted: boolean;
857
+ decision: "admit" | "deny" | "undeny";
834
858
  byUserId: UserId;
835
- }): Promise<void>;
859
+ }): Promise<MeetingAttendee>;
860
+ /** S4: admit everyone still waiting (not expired); returns the admitted rows. */
861
+ admitAll(meetingId: MeetingId, byUserId: UserId): Promise<readonly MeetingAttendee[]>;
836
862
  setLock(meetingId: MeetingId, locked: boolean, byUserId: UserId): Promise<MeetingRecord>;
837
863
  projectSegment(row: Row): TranscriptSegment;
838
864
  projectNote(row: Row): MeetingNote;
@@ -1121,14 +1147,15 @@ declare const MEET_EVENTS: {
1121
1147
  readonly cancel: "mx.call.cancel";
1122
1148
  /** You answered (or declined) on another device. Stop ringing here. */
1123
1149
  readonly settled: "mx.call.settled";
1124
- /** Someone is in the lobby. Hosts render the knock. */
1125
- readonly knock: "mx.lobby.knock";
1126
- /** A host decided. The knocker learns it here — they have no DB read. */
1127
- readonly admission: "mx.lobby.admission";
1128
- /** The room was locked or unlocked. */
1129
- readonly lock: "mx.room.lock";
1130
- /** Recording started or stopped. EVERY participant renders the indicator. */
1131
- readonly recording: "mx.room.recording";
1150
+ /**
1151
+ * 🚨 S4 (CORE-DESIGN §2.6): the ONE room-channel event — payload-free "something changed,
1152
+ * read again". Nothing a person must see rides it: a waiting person learns admitted /
1153
+ * denied / expired / ended by READING their row (`GET /v1/meet/state`) on a timer and on
1154
+ * every hint. The four payload broadcasts (`mx.lobby.knock`, `mx.lobby.admission`,
1155
+ * `mx.room.lock`, `mx.room.recording`) are gone with their senders and receivers. The
1156
+ * server publishes the same event on the same topic (aidream `admission.room_topic`).
1157
+ */
1158
+ readonly stateChanged: "mx.state.changed";
1132
1159
  };
1133
1160
  /**
1134
1161
  * 🚨 `mx.meeting.transcript` and `mx.meeting.note` WERE declared here and
@@ -1766,14 +1793,12 @@ interface MeetingSessionOptions {
1766
1793
  */
1767
1794
  onAdmitted?: (() => void) | undefined;
1768
1795
  /**
1769
- * 🚨 THE HOST DENIED *US*. Called once per denial verdict that names this
1770
- * knocker. Without it the waiting room kept promising "you will join
1771
- * automatically" to a person the host had already turned away (production
1772
- * 2026-09-27). The provider wires it to `engine.rejoin()`: the server then
1773
- * refuses the mint with its own sentence ("The host did not admit you…"),
1774
- * so the words on screen are the server's decision, never the client's guess.
1796
+ * S4: the meeting pass this device holds (`x-meet-pass`) — what the state read and
1797
+ * `/leave` are authorized by. Null when no pass is held yet.
1775
1798
  */
1776
- onDenied?: (() => void) | undefined;
1799
+ resolvePass?: (() => string | null) | undefined;
1800
+ /** S4: mint again (Ask to join again / Rejoin from the waiting screens). */
1801
+ rejoin?: (() => Promise<void>) | undefined;
1777
1802
  }
1778
1803
  interface MeetingSession {
1779
1804
  /** Subscribe to the room's out-of-band plane. Hosts see knocks; guests see verdicts. */
@@ -1786,10 +1811,24 @@ interface MeetingSession {
1786
1811
  * permanently missing the minute nobody noticed.
1787
1812
  */
1788
1813
  watchMeeting(meetingId: MeetingId): void;
1789
- /** A guest (or a late arrival at a locked room) announces themselves. */
1790
- knock(roomName: RoomName): void;
1791
1814
  admit(entry: LobbyEntry, admitted: boolean): Promise<void>;
1815
+ /** S4: lift a denial so the person may knock again (`meet_undeny`). */
1816
+ undeny(entry: LobbyEntry): Promise<void>;
1792
1817
  admitAll(): Promise<void>;
1818
+ /**
1819
+ * 🚨 S4 — THE WAIT READS SERVER TRUTH (CORE-DESIGN §2.6). While this tab waits, the state
1820
+ * read (`GET /v1/meet/state`) runs every `waiting_poll_seconds`, on every
1821
+ * `mx.state.changed` hint, on `online` and on visibility return. Admitted → a fresh mint
1822
+ * (`rejoin`); denied / expired / ended are what the row says, never a broadcast's guess.
1823
+ */
1824
+ startWaiting(): void;
1825
+ stopWaiting(): void;
1826
+ /** One state read now (idempotent while one is in flight). */
1827
+ readState(): Promise<void>;
1828
+ /** Stop waiting: the row becomes `withdrawn` (`POST /v1/meet/leave {intent: "withdraw"}`). */
1829
+ withdraw(): Promise<void>;
1830
+ /** Ask again after a denial or an expired knock (only offered when allowed). */
1831
+ askAgain(): Promise<void>;
1793
1832
  setLock(locked: boolean): Promise<MeetingRecord>;
1794
1833
  /** End it for everyone, through the server (MRI-A6). */
1795
1834
  endForEveryone(): Promise<EndMeetingResult>;
@@ -1925,6 +1964,12 @@ interface RoomToken {
1925
1964
  readonly sessionId: string | null;
1926
1965
  /** True when the server put this joiner in the lobby (D6). */
1927
1966
  readonly lobby: boolean;
1967
+ /**
1968
+ * S4: what the mint wrote on the person row — `admitted` · `knocking` · `waiting_host`.
1969
+ * A waiting person then reads `GET /v1/meet/state` every `pollSeconds`.
1970
+ */
1971
+ readonly admissionState?: AdmissionState | undefined;
1972
+ readonly pollSeconds?: number | undefined;
1928
1973
  /**
1929
1974
  * Meet wave 5: the breakout room this pass is for, or null for the main room. The
1930
1975
  * pass is still keyed by the MEETING's room name — it is this person's pass for the
@@ -2070,6 +2115,16 @@ declare const MEET_ROUTES: {
2070
2115
  readonly collab: "/api/v1/meet/collab";
2071
2116
  /** Meet wave 5: translate finished caption lines into this viewer's language. */
2072
2117
  readonly captionsTranslate: "/api/v1/meet/captions/translate";
2118
+ /**
2119
+ * S4 — THE STATE READ (CORE-DESIGN §2.6): `GET ?meeting_id=` with `x-meet-pass`. This
2120
+ * person's admission (lazy expiry applied), whether anyone who can admit is here, the run's
2121
+ * phase. Read every `waiting_poll_seconds` while waiting and on every `mx.state.changed`.
2122
+ */
2123
+ readonly state: "/api/v1/meet/state";
2124
+ /** S4: `withdraw` (stop waiting) or `leave` (close this tab); the pass may ride in the body. */
2125
+ readonly leave: "/api/v1/meet/leave";
2126
+ /** S4: a pass holder (guests included) saw the recording notice, for this run. */
2127
+ readonly consent: "/api/v1/meet/consent";
2073
2128
  };
2074
2129
  /** A `MEET_ROUTES` template with its `{meeting_id}` filled in, URL-encoded. */
2075
2130
  declare function meetingPath(template: string, meetingId: string): string;
@@ -3039,7 +3094,7 @@ declare function takeMoveRequest(store: CollabStoreLike): {
3039
3094
  */
3040
3095
  type ObservedRole = "host" | "cohost" | "participant" | "guest";
3041
3096
  /** `data-meet-phase` values this release renders (a subset of the contract's §2). */
3042
- type ObservedPhase = "resolving" | `refused:${string}` | "prejoin" | "joining" | "waiting:knocking" | "in_call" | "disconnected" | "ended";
3097
+ type ObservedPhase = "resolving" | `refused:${string}` | "prejoin" | "joining" | "waiting:knocking" | "waiting:host_not_started" | "denied" | "knock_expired" | "left" | "in_call" | "disconnected" | "ended";
3043
3098
  type ObservedConnection = "stable" | "reconnecting" | "server_unreachable";
3044
3099
  interface MeetObservation {
3045
3100
  readonly phase: ObservedPhase;