@ai-matrx/meet 0.11.46 → 0.11.48

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, e as ParticipantRole, k as AdmissionState, a1 as NoteTakerState, a as MeetParticipant, M as MeetingRecord, R as RoomName, d as CallInvite, a6 as ParticipantStanding, a3 as ObserversVisibleTo, S as StageLayout, L as LobbyEntry, aa as RecordingState, U as UserId, aF as RecordingSource, ae as TranscriptSegment, g as MeetingNote, W as WrapUpAnnouncement, j as CollabSnapshot, p as ConnectionQuality, h as MeetingId, b as MeetApi, f as CallMode, O as OrganizationId, m as CallId, n as CallState, Z as MeetingKind, a8 as RecordingPolicy, V as MeetingAttendee, a9 as RecordingRecord, a0 as MeetingSettings, X as MeetingChanges, a4 as OccurrenceOverride, $ as MeetingOccurrence, af as UpcomingOccurrence, Y as MeetingInvitee, I as InviteeInput, q as InviteeRole, ab as RsvpAnswer, ac as RsvpInvitation, c as MeetIdentity, C as CollabPanel } from './collab-D1TX5uf9.cjs';
2
- export { A as AccessTokenSource, l as CAPTION_LANGUAGES, o as CallablePerson, E as EMPTY_COLLAB, F as FILE_SESSION_PATH, J as JsonObject, r as JsonValue, s as MeetApiOptions, t as MeetApiRequest, u as MeetAppFocus, v as MeetBreakoutBroadcast, w as MeetBreakoutPlan, x as MeetBreakoutRoom, y as MeetCollabSettings, z as MeetFileMedia, B as MeetPoll, D as MeetPollOption, G as MeetPollState, H as MeetQuestion, K as MeetQuestionState, N as MeetStroke, Q as MeetingActivities, i as MeetingAppPanel, _ as MeetingNoteKind, a2 as ORGANIZATION_HEADER, a5 as OccurrenceState, a7 as ROLE_RANK, ad as RsvpState, T as TranscriptSource, ag as appPanelOf, ah as applyCollabPacket, ai as asCallId, aj as asMeetingId, ak as asOrganizationId, al as asParticipantIdentity, am as asRoomName, an as asUserId, ao as assignedRoom, ap as autoAssign, aq as breakoutClosingMs, ar as breakoutRemainingMs, as as captureHeldOf, at as collabFromState, au as createMeetApi, av as defaultCaptionLanguage, aw as fileDownloadPath, ax as focusFromRow, ay as isGuest, az as isHostRole, aA as isLinkFollower, aB as isObserverRole, aC as loadMeetingActivities, aD as scheduleSettingsPatch, aE as withItem } from './collab-D1TX5uf9.cjs';
1
+ import { P as ParticipantIdentity, e as ParticipantRole, k as AdmissionState, a1 as NoteTakerState, a as MeetParticipant, M as MeetingRecord, R as RoomName, d as CallInvite, a6 as ParticipantStanding, a3 as ObserversVisibleTo, S as StageLayout, L as LobbyEntry, aa as RecordingState, U as UserId, aF as RecordingSource, ae as TranscriptSegment, g as MeetingNote, W as WrapUpAnnouncement, j as CollabSnapshot, p as ConnectionQuality, h as MeetingId, b as MeetApi, f as CallMode, O as OrganizationId, m as CallId, n as CallState, Z as MeetingKind, a8 as RecordingPolicy, V as MeetingAttendee, a9 as RecordingRecord, a0 as MeetingSettings, X as MeetingChanges, a4 as OccurrenceOverride, $ as MeetingOccurrence, af as UpcomingOccurrence, Y as MeetingInvitee, I as InviteeInput, q as InviteeRole, ab as RsvpAnswer, ac as RsvpInvitation, c as MeetIdentity, C as CollabPanel } from './collab-Dk3r37MW.cjs';
2
+ export { A as AccessTokenSource, l as CAPTION_LANGUAGES, o as CallablePerson, E as EMPTY_COLLAB, F as FILE_SESSION_PATH, J as JsonObject, r as JsonValue, s as MeetApiOptions, t as MeetApiRequest, u as MeetAppFocus, v as MeetBreakoutBroadcast, w as MeetBreakoutPlan, x as MeetBreakoutRoom, y as MeetCollabSettings, z as MeetFileMedia, B as MeetPoll, D as MeetPollOption, G as MeetPollState, H as MeetQuestion, K as MeetQuestionState, N as MeetStroke, Q as MeetingActivities, i as MeetingAppPanel, _ as MeetingNoteKind, a2 as ORGANIZATION_HEADER, a5 as OccurrenceState, a7 as ROLE_RANK, ad as RsvpState, T as TranscriptSource, ag as appPanelOf, ah as applyCollabPacket, ai as asCallId, aj as asMeetingId, ak as asOrganizationId, al as asParticipantIdentity, am as asRoomName, an as asUserId, ao as assignedRoom, ap as autoAssign, aq as breakoutClosingMs, ar as breakoutRemainingMs, as as captureHeldOf, at as collabFromState, au as createMeetApi, av as defaultCaptionLanguage, aw as fileDownloadPath, ax as focusFromRow, ay as isGuest, az as isHostRole, aA as isLinkFollower, aB as isObserverRole, aC as loadMeetingActivities, aD as scheduleSettingsPatch, aE as withItem } from './collab-Dk3r37MW.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';
@@ -172,13 +172,21 @@ declare function leaveChoices(args: {
172
172
  type ChatMode = "everyone" | "hosts_only" | "off";
173
173
  type AvLock = "off" | "mic" | "camera" | "both";
174
174
  type RecordingConsent = "notice" | "ok_or_leave" | "view_only_until_agree";
175
+ /** Who may share a screen (`share_who_can`) and how many may at once (`share_concurrency`). */
176
+ type ShareWhoCan = "everyone" | "host_only" | "org" | "presenters";
177
+ type ShareConcurrency = "one_takeover" | "one_replace" | "multiple";
178
+ /** What remains when no host or co-host is in the room (`headless_powers`, CORE-DESIGN §4.2). */
179
+ type HeadlessPowers = "members_admit" | "none" | "cohosts_only";
175
180
  interface LivePolicy {
181
+ readonly headlessPowers: HeadlessPowers;
176
182
  readonly chatMode: ChatMode;
177
183
  readonly avLock: AvLock;
178
184
  /** 0 = no limit. */
179
185
  readonly timeLimitMinutes: number;
180
186
  readonly timeLimitWarningMinutes: number;
181
187
  readonly recordingConsent: RecordingConsent;
188
+ readonly shareWhoCan: ShareWhoCan;
189
+ readonly shareConcurrency: ShareConcurrency;
182
190
  }
183
191
 
184
192
  /**
@@ -689,15 +697,25 @@ interface MeetWaiting {
689
697
  readonly liveVersion: number;
690
698
  }
691
699
  /** The core's `connection` region (CORE-DESIGN §3.2) — never a phase. */
700
+ interface LocalNetwork {
701
+ readonly path: "direct" | "restricted" | "unknown";
702
+ readonly quality: "good" | "poor" | "unknown";
703
+ readonly videoPaused: boolean;
704
+ }
692
705
  type ConnectionRegion = "stable" | "signal_reconnecting" | "reconnecting" | "offline" | "server_unreachable";
693
706
  /**
694
707
  * The core's `share` region (CORE-DESIGN §3.2/§3.3 SA). A refused share is a situation the person
695
708
  * is in — a notice (`share-unavailable`), never a phase.
696
709
  */
697
710
  interface ShareRegion {
698
- readonly state: "none" | "picking" | "presenting" | "refused";
699
- /** Why a share was refused: this browser cannot share, the system blocks it, or it failed. */
700
- readonly reason: "unsupported" | "blocked" | "failed" | null;
711
+ readonly state: "none" | "picking" | "presenting" | "refused" | "ended";
712
+ /**
713
+ * Why a share was refused (this browser cannot share, the system blocks it, or it failed) or, for
714
+ * `ended`, why the server took it down: someone else presented instead, or the host's rule no longer lets this person share.
715
+ */
716
+ readonly reason: "unsupported" | "blocked" | "failed" | "replaced" | "not_allowed" | null;
717
+ /** `ended` / `replaced`: who presents now. */
718
+ readonly by?: string;
701
719
  /** The fix, in the core's words (system setting, administrator policy, …), or null. */
702
720
  readonly remedy: string | null;
703
721
  readonly at: number;
@@ -725,6 +743,13 @@ interface MeetSnapshot {
725
743
  * drop outlasts `reconnect_banner_delay_ms` (the connection supervisor sets it, §3.3 CS).
726
744
  */
727
745
  readonly connectionBanner: boolean;
746
+ /**
747
+ * P1 connection-network — THIS tab's own path, as the core judged it from its WebRTC stats
748
+ * (`network-health.ts`): `restricted` = relayed or TCP-only (`net-udp-blocked`), `quality` =
749
+ * the self-assessment (`net-quality-self`), `videoPaused` = the camera was paused by the
750
+ * network to keep the audio (`net-video-auto-off`). The room engine is the one writer.
751
+ */
752
+ readonly localNetwork: LocalNetwork;
728
753
  /** The `share` region. */
729
754
  readonly share: ShareRegion;
730
755
  /**
@@ -1960,6 +1985,44 @@ declare function computeStage(args: StageArgs): Stage;
1960
1985
  /** Column count for a grid of N tiles — the shape that keeps tiles squarest. */
1961
1986
  declare function gridColumns(count: number): number;
1962
1987
 
1988
+ /**
1989
+ * NETWORK HEALTH (CORE-DESIGN §3.3 CS, P1 connection-network) — the pure rules behind what each
1990
+ * person sees when a network degrades. No socket, no timer, no browser global: the driver hands
1991
+ * in readings, the engine hands in the clock, and every rule here is provable in a node test.
1992
+ *
1993
+ * Why the core judges quality itself and does not only repeat LiveKit's `ConnectionQuality`:
1994
+ * LiveKit scores a TCP/TURN path with 800 ms of round trip as "good" (no packets are lost on
1995
+ * TCP — they are just late), and it keeps a participant whose cable was pulled "good" for 25 s
1996
+ * and more. Google Meet documents media quality degrading at RTT ≥ 300 ms; that is the bar here.
1997
+ *
1998
+ * Four rules:
1999
+ * 1. **Self-assessment** (`createSelfAssessor`): this tab's own path, from its WebRTC stats —
2000
+ * round trip, loss — with hysteresis so the reading does not flap.
2001
+ * 2. **The path** (`pathOf`): media relayed over TURN or carried over TCP is a restricted network
2002
+ * (`net-udp-blocked`): the call works, quality may be reduced.
2003
+ * 3. **Liveness** (`createLivenessTracker`): every client says "alive" on a light data heartbeat
2004
+ * that carries its own reading and whether its video is paused. A person who goes silent past
2005
+ * `staleAfterMs` is shown `reconnecting` to everyone else (`net-others-see-drop`) — long before
2006
+ * the media server gives up on them. A client that never sent a heartbeat (an agent, an older
2007
+ * client) is never judged by it.
2008
+ * 4. **Video auto-off** (`createVideoAutoOff`): a poor reading that lasts
2009
+ * `video_auto_off_after_poor_seconds` pauses this person's camera so their audio survives
2010
+ * (`net-video-auto-off`); a person who turns it back on is not paused again until the path has
2011
+ * recovered once.
2012
+ */
2013
+
2014
+ /** One sample of this tab's WebRTC path, as the driver read it from `getStats()`. */
2015
+ interface NetworkReading {
2016
+ /** Selected candidate pair's current round trip (ms), or null when not known. */
2017
+ readonly rttMs: number | null;
2018
+ /** Fraction of packets lost since the previous sample (0..1), or null. */
2019
+ readonly lossRatio: number | null;
2020
+ /** The selected local candidate is a TURN relay. */
2021
+ readonly relayed: boolean | null;
2022
+ /** The selected local candidate carries media over TCP. */
2023
+ readonly tcp: boolean | null;
2024
+ }
2025
+
1963
2026
  /**
1964
2027
  * THE MEDIA SEAM — the ONE interface the room engine talks to.
1965
2028
  *
@@ -2062,6 +2125,12 @@ interface RoomDriverHandlers {
2062
2125
  devicesChanged?(): void;
2063
2126
  /** S6c — the SDK could not acquire or keep a local device. `kind` when the SDK knows it. */
2064
2127
  mediaDeviceError?(error: unknown, kind: "audioinput" | "videoinput" | null): void;
2128
+ /**
2129
+ * P1 connection-network — one sample of THIS tab's WebRTC path (round trip, loss, relay/TCP),
2130
+ * read from the peer connections' stats every couple of seconds while connected. The rules
2131
+ * that turn samples into what people see are `network-health.ts`. Optional for older drivers.
2132
+ */
2133
+ networkReading?(reading: NetworkReading): void;
2065
2134
  }
2066
2135
  /** A camera background effect. `image` replaces the background with `imageUrl`. */
2067
2136
  type VideoEffect = {
@@ -2782,6 +2851,11 @@ interface ConnectionPolicy {
2782
2851
  readonly autoRejoinMaxAttempts: number;
2783
2852
  /** `reconnect_grace_seconds`: how long others keep a dropped person's `reconnecting` tile. */
2784
2853
  readonly reconnectGraceSeconds: number;
2854
+ /**
2855
+ * `video_auto_off_after_poor_seconds`: a poor path that lasts this long pauses the person's
2856
+ * camera so their audio survives (`net-video-auto-off`); 0 = never.
2857
+ */
2858
+ readonly videoAutoOffAfterPoorSeconds: number;
2785
2859
  }
2786
2860
  /** The knob defaults (§4.3) — what an older server that sends nothing gets. */
2787
2861
  declare const DEFAULT_CONNECTION_POLICY: ConnectionPolicy;
@@ -3910,6 +3984,7 @@ declare function activityAttention(collab: CollabSnapshot | null, isHost: boolea
3910
3984
  interface CollabRuntime {
3911
3985
  readonly inRoom: {
3912
3986
  collab(request: CollabRequest): Promise<CollabResult>;
3987
+ loadCollab?(): Promise<void>;
3913
3988
  };
3914
3989
  readonly engine: {
3915
3990
  moveToBreakout(roomId: string | null): Promise<unknown>;
package/dist/core.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as ParticipantIdentity, e as ParticipantRole, k as AdmissionState, a1 as NoteTakerState, a as MeetParticipant, M as MeetingRecord, R as RoomName, d as CallInvite, a6 as ParticipantStanding, a3 as ObserversVisibleTo, S as StageLayout, L as LobbyEntry, aa as RecordingState, U as UserId, aF as RecordingSource, ae as TranscriptSegment, g as MeetingNote, W as WrapUpAnnouncement, j as CollabSnapshot, p as ConnectionQuality, h as MeetingId, b as MeetApi, f as CallMode, O as OrganizationId, m as CallId, n as CallState, Z as MeetingKind, a8 as RecordingPolicy, V as MeetingAttendee, a9 as RecordingRecord, a0 as MeetingSettings, X as MeetingChanges, a4 as OccurrenceOverride, $ as MeetingOccurrence, af as UpcomingOccurrence, Y as MeetingInvitee, I as InviteeInput, q as InviteeRole, ab as RsvpAnswer, ac as RsvpInvitation, c as MeetIdentity, C as CollabPanel } from './collab-D1TX5uf9.js';
2
- export { A as AccessTokenSource, l as CAPTION_LANGUAGES, o as CallablePerson, E as EMPTY_COLLAB, F as FILE_SESSION_PATH, J as JsonObject, r as JsonValue, s as MeetApiOptions, t as MeetApiRequest, u as MeetAppFocus, v as MeetBreakoutBroadcast, w as MeetBreakoutPlan, x as MeetBreakoutRoom, y as MeetCollabSettings, z as MeetFileMedia, B as MeetPoll, D as MeetPollOption, G as MeetPollState, H as MeetQuestion, K as MeetQuestionState, N as MeetStroke, Q as MeetingActivities, i as MeetingAppPanel, _ as MeetingNoteKind, a2 as ORGANIZATION_HEADER, a5 as OccurrenceState, a7 as ROLE_RANK, ad as RsvpState, T as TranscriptSource, ag as appPanelOf, ah as applyCollabPacket, ai as asCallId, aj as asMeetingId, ak as asOrganizationId, al as asParticipantIdentity, am as asRoomName, an as asUserId, ao as assignedRoom, ap as autoAssign, aq as breakoutClosingMs, ar as breakoutRemainingMs, as as captureHeldOf, at as collabFromState, au as createMeetApi, av as defaultCaptionLanguage, aw as fileDownloadPath, ax as focusFromRow, ay as isGuest, az as isHostRole, aA as isLinkFollower, aB as isObserverRole, aC as loadMeetingActivities, aD as scheduleSettingsPatch, aE as withItem } from './collab-D1TX5uf9.js';
1
+ import { P as ParticipantIdentity, e as ParticipantRole, k as AdmissionState, a1 as NoteTakerState, a as MeetParticipant, M as MeetingRecord, R as RoomName, d as CallInvite, a6 as ParticipantStanding, a3 as ObserversVisibleTo, S as StageLayout, L as LobbyEntry, aa as RecordingState, U as UserId, aF as RecordingSource, ae as TranscriptSegment, g as MeetingNote, W as WrapUpAnnouncement, j as CollabSnapshot, p as ConnectionQuality, h as MeetingId, b as MeetApi, f as CallMode, O as OrganizationId, m as CallId, n as CallState, Z as MeetingKind, a8 as RecordingPolicy, V as MeetingAttendee, a9 as RecordingRecord, a0 as MeetingSettings, X as MeetingChanges, a4 as OccurrenceOverride, $ as MeetingOccurrence, af as UpcomingOccurrence, Y as MeetingInvitee, I as InviteeInput, q as InviteeRole, ab as RsvpAnswer, ac as RsvpInvitation, c as MeetIdentity, C as CollabPanel } from './collab-Dk3r37MW.js';
2
+ export { A as AccessTokenSource, l as CAPTION_LANGUAGES, o as CallablePerson, E as EMPTY_COLLAB, F as FILE_SESSION_PATH, J as JsonObject, r as JsonValue, s as MeetApiOptions, t as MeetApiRequest, u as MeetAppFocus, v as MeetBreakoutBroadcast, w as MeetBreakoutPlan, x as MeetBreakoutRoom, y as MeetCollabSettings, z as MeetFileMedia, B as MeetPoll, D as MeetPollOption, G as MeetPollState, H as MeetQuestion, K as MeetQuestionState, N as MeetStroke, Q as MeetingActivities, i as MeetingAppPanel, _ as MeetingNoteKind, a2 as ORGANIZATION_HEADER, a5 as OccurrenceState, a7 as ROLE_RANK, ad as RsvpState, T as TranscriptSource, ag as appPanelOf, ah as applyCollabPacket, ai as asCallId, aj as asMeetingId, ak as asOrganizationId, al as asParticipantIdentity, am as asRoomName, an as asUserId, ao as assignedRoom, ap as autoAssign, aq as breakoutClosingMs, ar as breakoutRemainingMs, as as captureHeldOf, at as collabFromState, au as createMeetApi, av as defaultCaptionLanguage, aw as fileDownloadPath, ax as focusFromRow, ay as isGuest, az as isHostRole, aA as isLinkFollower, aB as isObserverRole, aC as loadMeetingActivities, aD as scheduleSettingsPatch, aE as withItem } from './collab-Dk3r37MW.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';
@@ -172,13 +172,21 @@ declare function leaveChoices(args: {
172
172
  type ChatMode = "everyone" | "hosts_only" | "off";
173
173
  type AvLock = "off" | "mic" | "camera" | "both";
174
174
  type RecordingConsent = "notice" | "ok_or_leave" | "view_only_until_agree";
175
+ /** Who may share a screen (`share_who_can`) and how many may at once (`share_concurrency`). */
176
+ type ShareWhoCan = "everyone" | "host_only" | "org" | "presenters";
177
+ type ShareConcurrency = "one_takeover" | "one_replace" | "multiple";
178
+ /** What remains when no host or co-host is in the room (`headless_powers`, CORE-DESIGN §4.2). */
179
+ type HeadlessPowers = "members_admit" | "none" | "cohosts_only";
175
180
  interface LivePolicy {
181
+ readonly headlessPowers: HeadlessPowers;
176
182
  readonly chatMode: ChatMode;
177
183
  readonly avLock: AvLock;
178
184
  /** 0 = no limit. */
179
185
  readonly timeLimitMinutes: number;
180
186
  readonly timeLimitWarningMinutes: number;
181
187
  readonly recordingConsent: RecordingConsent;
188
+ readonly shareWhoCan: ShareWhoCan;
189
+ readonly shareConcurrency: ShareConcurrency;
182
190
  }
183
191
 
184
192
  /**
@@ -689,15 +697,25 @@ interface MeetWaiting {
689
697
  readonly liveVersion: number;
690
698
  }
691
699
  /** The core's `connection` region (CORE-DESIGN §3.2) — never a phase. */
700
+ interface LocalNetwork {
701
+ readonly path: "direct" | "restricted" | "unknown";
702
+ readonly quality: "good" | "poor" | "unknown";
703
+ readonly videoPaused: boolean;
704
+ }
692
705
  type ConnectionRegion = "stable" | "signal_reconnecting" | "reconnecting" | "offline" | "server_unreachable";
693
706
  /**
694
707
  * The core's `share` region (CORE-DESIGN §3.2/§3.3 SA). A refused share is a situation the person
695
708
  * is in — a notice (`share-unavailable`), never a phase.
696
709
  */
697
710
  interface ShareRegion {
698
- readonly state: "none" | "picking" | "presenting" | "refused";
699
- /** Why a share was refused: this browser cannot share, the system blocks it, or it failed. */
700
- readonly reason: "unsupported" | "blocked" | "failed" | null;
711
+ readonly state: "none" | "picking" | "presenting" | "refused" | "ended";
712
+ /**
713
+ * Why a share was refused (this browser cannot share, the system blocks it, or it failed) or, for
714
+ * `ended`, why the server took it down: someone else presented instead, or the host's rule no longer lets this person share.
715
+ */
716
+ readonly reason: "unsupported" | "blocked" | "failed" | "replaced" | "not_allowed" | null;
717
+ /** `ended` / `replaced`: who presents now. */
718
+ readonly by?: string;
701
719
  /** The fix, in the core's words (system setting, administrator policy, …), or null. */
702
720
  readonly remedy: string | null;
703
721
  readonly at: number;
@@ -725,6 +743,13 @@ interface MeetSnapshot {
725
743
  * drop outlasts `reconnect_banner_delay_ms` (the connection supervisor sets it, §3.3 CS).
726
744
  */
727
745
  readonly connectionBanner: boolean;
746
+ /**
747
+ * P1 connection-network — THIS tab's own path, as the core judged it from its WebRTC stats
748
+ * (`network-health.ts`): `restricted` = relayed or TCP-only (`net-udp-blocked`), `quality` =
749
+ * the self-assessment (`net-quality-self`), `videoPaused` = the camera was paused by the
750
+ * network to keep the audio (`net-video-auto-off`). The room engine is the one writer.
751
+ */
752
+ readonly localNetwork: LocalNetwork;
728
753
  /** The `share` region. */
729
754
  readonly share: ShareRegion;
730
755
  /**
@@ -1960,6 +1985,44 @@ declare function computeStage(args: StageArgs): Stage;
1960
1985
  /** Column count for a grid of N tiles — the shape that keeps tiles squarest. */
1961
1986
  declare function gridColumns(count: number): number;
1962
1987
 
1988
+ /**
1989
+ * NETWORK HEALTH (CORE-DESIGN §3.3 CS, P1 connection-network) — the pure rules behind what each
1990
+ * person sees when a network degrades. No socket, no timer, no browser global: the driver hands
1991
+ * in readings, the engine hands in the clock, and every rule here is provable in a node test.
1992
+ *
1993
+ * Why the core judges quality itself and does not only repeat LiveKit's `ConnectionQuality`:
1994
+ * LiveKit scores a TCP/TURN path with 800 ms of round trip as "good" (no packets are lost on
1995
+ * TCP — they are just late), and it keeps a participant whose cable was pulled "good" for 25 s
1996
+ * and more. Google Meet documents media quality degrading at RTT ≥ 300 ms; that is the bar here.
1997
+ *
1998
+ * Four rules:
1999
+ * 1. **Self-assessment** (`createSelfAssessor`): this tab's own path, from its WebRTC stats —
2000
+ * round trip, loss — with hysteresis so the reading does not flap.
2001
+ * 2. **The path** (`pathOf`): media relayed over TURN or carried over TCP is a restricted network
2002
+ * (`net-udp-blocked`): the call works, quality may be reduced.
2003
+ * 3. **Liveness** (`createLivenessTracker`): every client says "alive" on a light data heartbeat
2004
+ * that carries its own reading and whether its video is paused. A person who goes silent past
2005
+ * `staleAfterMs` is shown `reconnecting` to everyone else (`net-others-see-drop`) — long before
2006
+ * the media server gives up on them. A client that never sent a heartbeat (an agent, an older
2007
+ * client) is never judged by it.
2008
+ * 4. **Video auto-off** (`createVideoAutoOff`): a poor reading that lasts
2009
+ * `video_auto_off_after_poor_seconds` pauses this person's camera so their audio survives
2010
+ * (`net-video-auto-off`); a person who turns it back on is not paused again until the path has
2011
+ * recovered once.
2012
+ */
2013
+
2014
+ /** One sample of this tab's WebRTC path, as the driver read it from `getStats()`. */
2015
+ interface NetworkReading {
2016
+ /** Selected candidate pair's current round trip (ms), or null when not known. */
2017
+ readonly rttMs: number | null;
2018
+ /** Fraction of packets lost since the previous sample (0..1), or null. */
2019
+ readonly lossRatio: number | null;
2020
+ /** The selected local candidate is a TURN relay. */
2021
+ readonly relayed: boolean | null;
2022
+ /** The selected local candidate carries media over TCP. */
2023
+ readonly tcp: boolean | null;
2024
+ }
2025
+
1963
2026
  /**
1964
2027
  * THE MEDIA SEAM — the ONE interface the room engine talks to.
1965
2028
  *
@@ -2062,6 +2125,12 @@ interface RoomDriverHandlers {
2062
2125
  devicesChanged?(): void;
2063
2126
  /** S6c — the SDK could not acquire or keep a local device. `kind` when the SDK knows it. */
2064
2127
  mediaDeviceError?(error: unknown, kind: "audioinput" | "videoinput" | null): void;
2128
+ /**
2129
+ * P1 connection-network — one sample of THIS tab's WebRTC path (round trip, loss, relay/TCP),
2130
+ * read from the peer connections' stats every couple of seconds while connected. The rules
2131
+ * that turn samples into what people see are `network-health.ts`. Optional for older drivers.
2132
+ */
2133
+ networkReading?(reading: NetworkReading): void;
2065
2134
  }
2066
2135
  /** A camera background effect. `image` replaces the background with `imageUrl`. */
2067
2136
  type VideoEffect = {
@@ -2782,6 +2851,11 @@ interface ConnectionPolicy {
2782
2851
  readonly autoRejoinMaxAttempts: number;
2783
2852
  /** `reconnect_grace_seconds`: how long others keep a dropped person's `reconnecting` tile. */
2784
2853
  readonly reconnectGraceSeconds: number;
2854
+ /**
2855
+ * `video_auto_off_after_poor_seconds`: a poor path that lasts this long pauses the person's
2856
+ * camera so their audio survives (`net-video-auto-off`); 0 = never.
2857
+ */
2858
+ readonly videoAutoOffAfterPoorSeconds: number;
2785
2859
  }
2786
2860
  /** The knob defaults (§4.3) — what an older server that sends nothing gets. */
2787
2861
  declare const DEFAULT_CONNECTION_POLICY: ConnectionPolicy;
@@ -3910,6 +3984,7 @@ declare function activityAttention(collab: CollabSnapshot | null, isHost: boolea
3910
3984
  interface CollabRuntime {
3911
3985
  readonly inRoom: {
3912
3986
  collab(request: CollabRequest): Promise<CollabResult>;
3987
+ loadCollab?(): Promise<void>;
3913
3988
  };
3914
3989
  readonly engine: {
3915
3990
  moveToBreakout(roomId: string | null): Promise<unknown>;