@ai-matrx/meet 0.7.7 → 0.7.8
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 +37 -0
- package/dist/index.cjs +129 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +79 -50
- package/dist/index.d.ts +79 -50
- package/dist/index.js +129 -50
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +827 -701
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +803 -677
- package/dist/react.js.map +1 -1
- package/dist/styles.css +18 -0
- package/package.json +4 -4
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react/provider.tsx","../src/core/ai.ts","../src/core/errors.ts","../src/core/tokens.ts","../src/core/api.ts","../src/core/channels.ts","../src/core/slot.ts","../src/core/types.ts","../src/core/calls.ts","../src/core/devices.ts","../src/core/names.ts","../src/core/recording.ts","../src/core/attendance.ts","../src/core/transcript.ts","../src/core/store.ts","../src/core/meetings.ts","../src/core/repository.ts","../src/core/session-identity.ts","../src/core/room-events.ts","../src/core/note-taker.ts","../src/core/room-driver.ts","../src/core/room.ts","../src/core/effects.ts","../src/core/in-room.ts","../src/core/livekit-driver.ts","../src/react/hooks.ts","../src/core/layout.ts","../src/core/record.ts","../src/react/components.tsx","../src/core/format.ts","../src/react/icons.tsx","../src/core/invitations.ts","../src/core/after.ts","../src/core/management.ts"],"sourcesContent":["\"use client\";\n\n/**\n * `<MeetProvider>` — the one place an app wires calls and meetings (R7).\n *\n * THE ONE-HOUR INTEGRATION CONTRACT is this component's job: a host passes a\n * Supabase client, who they are, their org, and aidream's base URL. Everything\n * else — the repository, the realtime manager and its three channels, the token\n * client, the room engine, the call center, the meeting session, the recording\n * controller, the device manager, the AI surface — is constructed and owned\n * here.\n *\n * What a host may inject is IDENTITY and app chrome: session source, a\n * navigator, a notification sink. It may NOT inject an agent id — as of 0.3.0\n * there is no prop for one, because which agent answers is a Mandate binding\n * the SERVER resolves (D2). What a host must NEVER have to inject is\n * behavior — if you find yourself catching a package error, retrying a package\n * call, or branching on a package quirk in host code, that logic belongs in\n * here (C22).\n *\n * 🚨 THE PROVIDER'S LIFETIME IS `client` + the SESSION'S user (or `guestName`)\n * + `organizationId` + `baseUrl`, AND NOTHING ELSE. Hosts pass fresh function\n * literals for `onDiagnostic` and `accessToken` on every render; keying the\n * runtime on those identities would tear down and rebuild every channel — and\n * drop the call in progress — on every parent re-render.\n *\n * 🚨 THERE IS NO `userId` PROP, AND THERE NEVER WILL BE AGAIN (DD-240, 0.6.0).\n * The acting user is read from `client`'s own session — the same client that\n * mints the JWT on every request — so the id in a `p_user_id` argument and the\n * id in the token cannot disagree. Through 0.5.x this was a prop, every host\n * filled it from a copy in its own state, and a rotated auth cookie left that\n * copy naming an account the tab could no longer prove it was:\n * `meet_pending_call_invites` refused it at 403 with \"the acting user … is not\n * the authenticated user\", 8.8 h and 32.9 h into two tabs' lives. The whole\n * story is in `../core/session-identity.ts`.\n *\n * 🚨 A GUEST IS A FIRST-CLASS IDENTITY (D6), not a degraded user. Pass\n * `guestName` and the provider builds a runtime with no calling surface and no\n * host powers, which is exactly what a link-follower needs — and, because a\n * guest has no account at all, the guest lane never reads the session. Nothing\n * downstream branches on \"is this a real user\".\n */\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from \"react\";\nimport {\n RealtimeProvider,\n useIsRealtimeProviderMounted,\n useRealtimeManager,\n} from \"@ai-matrx/realtime/react\";\nimport type { MessagingSupabaseClient } from \"@ai-matrx/messaging\";\nimport { createMeetAi, type MeetAi } from \"../core/ai\";\nimport { createMeetApi, type MeetApi } from \"../core/api\";\nimport { createCallCenter, type CallCenter } from \"../core/calls\";\nimport {\n createDeviceManager,\n createWebDeviceStorage,\n type DeviceManager,\n type DeviceSnapshot,\n type MediaDevicesLike,\n} from \"../core/devices\";\nimport { createMeetingSession, type MeetingSession } from \"../core/meetings\";\nimport { createRecordingController, type RecordingController } from \"../core/recording\";\nimport { createMeetRepository, type MeetRepository } from \"../core/repository\";\nimport {\n createSessionIdentity,\n SERVER_SESSION_IDENTITY,\n type SessionIdentitySnapshot,\n} from \"../core/session-identity\";\nimport { createRoomEngine, type RoomEngine } from \"../core/room\";\nimport { createWebEffectsStorage } from \"../core/effects\";\nimport { createInRoomClient, type InRoomClient } from \"../core/in-room\";\nimport { createLiveKitDriver } from \"../core/livekit-driver\";\nimport type { RoomDriverFactory } from \"../core/room-driver\";\nimport {\n createMeetStore,\n effectiveRole,\n type MeetSnapshot,\n type MeetStore,\n} from \"../core/store\";\nimport {\n createTokenClient,\n createWebRoomTokenStorage,\n type AccessTokenSource,\n type TokenClient,\n} from \"../core/tokens\";\nimport {\n asOrganizationId,\n isHostRole,\n type CallInvite,\n type MeetIdentity,\n type ParticipantRole,\n type UserId,\n} from \"../core/types\";\n\nexport interface MeetDiagnostic {\n readonly level: \"info\" | \"warn\" | \"error\";\n readonly message: string;\n readonly remedy?: string | undefined;\n}\n\nexport interface MeetHost {\n readonly store: MeetStore;\n readonly engine: RoomEngine;\n readonly calls: CallCenter | null;\n readonly meetings: MeetingSession;\n /**\n * Meet wave 2: host moderation and the SAVED chat, both decided and written by\n * the server (`core/in-room.ts`). A guest's calls carry their room pass.\n */\n readonly inRoom: InRoomClient;\n readonly recording: RecordingController;\n readonly devices: DeviceManager;\n readonly repository: MeetRepository;\n readonly tokens: TokenClient;\n /**\n * 🚨 NEVER NULL as of 0.3.0. Through 0.2.1 this was `null` unless the host\n * injected a transport AND four agent ids, so the meeting assistant silently\n * did not exist for any app that had not filled in a config line. The\n * capability is the SERVER's now: if a Mandate has no Holder bound, the\n * server refuses with a sentence naming the Mandate admin, and that sentence\n * is what the panel shows. Absence is a fact the server states, never a prop\n * a host forgot.\n */\n readonly ai: MeetAi;\n /**\n * 🚨 THE ONE WAY ANYTHING IN THIS PACKAGE TALKS TO AIDREAM (MRI-A16). Every\n * request it builds carries `x-organization-id`; a request built any other\n * way is refused by the org-admission middleware with 400\n * `organization_required`, and `core/api.test.ts` fails the build if a second\n * way appears. Playing a recording — `GET /files/{id}/download` — goes\n * through here too, which is the defect this replaced.\n */\n readonly api: MeetApi;\n readonly identity: MeetIdentity;\n readonly baseUrl: string;\n /**\n * The host's session source, as handed to `<MeetProvider>`. Exposed for the\n * host's own diagnostics; package code reaches aidream through `api`.\n */\n readonly accessToken: AccessTokenSource;\n readonly report: (event: MeetDiagnostic) => void;\n}\n\nconst MeetContext = createContext<MeetHost | null>(null);\n\nexport interface MeetProviderProps {\n /**\n * Any Supabase client. `null` while the host is still resolving one.\n *\n * 🚨 DELIBERATELY THE SHALLOW SHAPE (0.2.1) — pass the\n * `SupabaseClient<Database>` you already have, with no cast. The rich\n * internal contract sent tsc into `TS2589` for any host with generated\n * Supabase types; see `core/repository.ts`'s header for the whole story.\n */\n client: MessagingSupabaseClient | null | undefined;\n /** aidream's base URL. LiveKit credentials live THERE, never here. */\n baseUrl: string;\n /**\n * A guest's typed name — and the ONE way to declare the guest lane (D6).\n * With it, this mount is a link-follower's room: no session is read, no\n * calling surface is built, and nothing user-scoped is ever issued. Without\n * it, the acting user is whoever `client`'s session says it is.\n *\n * 🚨 There is NO `userId` prop. See this file's header and\n * `../core/session-identity.ts`.\n */\n guestName?: string | null | undefined;\n organizationId: string | null | undefined;\n displayName?: string | undefined;\n avatarUrl?: string | null | undefined;\n /** The bearer token source for aidream calls. */\n accessToken: AccessTokenSource;\n /** Swap the media driver. Defaults to LiveKit — there is no reason to. */\n driverFactory?: RoomDriverFactory | undefined;\n /** A call is ringing this device — for a sound, a toast, or a badge. */\n onIncomingCall?: ((invite: CallInvite) => void) | undefined;\n onDiagnostic?: ((event: MeetDiagnostic) => void) | undefined;\n ringTimeoutMs?: number | undefined;\n children: ReactNode;\n}\n\nfunction defaultDiagnostics(event: MeetDiagnostic): void {\n const line = `[@ai-matrx/meet] ${event.message}${\n event.remedy !== undefined ? `\\n → ${event.remedy}` : \"\"\n }`;\n if (event.level === \"error\") console.error(line);\n else if (event.level === \"warn\") console.warn(line);\n else console.info(line);\n}\n\n/** A stable per-device id, so a reconnect keeps ONE LiveKit identity. */\nfunction deviceId(): string {\n const storage = (globalThis as { localStorage?: Storage }).localStorage;\n const key = \"mx.meet.device\";\n try {\n const existing = storage?.getItem(key);\n if (existing !== null && existing !== undefined && existing.length > 0) return existing;\n const created = Math.random().toString(36).slice(2, 14);\n storage?.setItem(key, created);\n return created;\n } catch {\n return Math.random().toString(36).slice(2, 14);\n }\n}\n\n/**\n * THE ONE SESSION READ. Subscribed per client, torn down with it, and honest\n * about the `resolving` window in between — see `../core/session-identity.ts`\n * for the class this closes.\n *\n * `client === null` (the guest lane, or a host still resolving one) never opens\n * a subscription at all: a link-follower has no account to read.\n */\nfunction useSessionIdentity(\n client: MessagingSupabaseClient | null | undefined,\n report: (event: MeetDiagnostic) => void,\n): SessionIdentitySnapshot {\n const [snapshot, setSnapshot] = useState<SessionIdentitySnapshot>(SERVER_SESSION_IDENTITY);\n\n useEffect(() => {\n if (client == null) {\n setSnapshot(SERVER_SESSION_IDENTITY);\n return undefined;\n }\n const identity = createSessionIdentity({ client, onDiagnostic: report });\n setSnapshot(identity.snapshot());\n const unsubscribe = identity.subscribe(() => setSnapshot(identity.snapshot()));\n return () => {\n unsubscribe();\n identity.dispose();\n };\n }, [client, report]);\n\n return snapshot;\n}\n\n/** A guest lane is declared by a NON-EMPTY typed name, and by nothing else. */\nfunction guestLaneName(guestName: string | null | undefined): string | null {\n return typeof guestName === \"string\" && guestName.trim().length > 0 ? guestName : null;\n}\n\nexport function MeetProvider(props: MeetProviderProps): ReactNode {\n const { client } = props;\n\n // Live ref so a host's fresh function literal per render never becomes part\n // of anything's lifetime, while callbacks still see the CURRENT one.\n const diagnosticRef = useRef(props.onDiagnostic);\n diagnosticRef.current = props.onDiagnostic;\n const report = useCallback((event: MeetDiagnostic): void => {\n (diagnosticRef.current ?? defaultDiagnostics)(event);\n }, []);\n\n // 🚨 NOTHING FAILS SILENTLY. A host still passing the 0.5.x `userId` prop —\n // a stale bundle, a JS consumer tsc never checked — is told, once, that it is\n // ignored and why. Silently dropping it would look exactly like the bug.\n const legacyUserIdReported = useRef(false);\n const legacyUserId = (props as { userId?: unknown }).userId;\n useEffect(() => {\n if (legacyUserId === undefined || legacyUserId === null) return;\n if (legacyUserIdReported.current) return;\n legacyUserIdReported.current = true;\n report({\n level: \"error\",\n message:\n \"<MeetProvider userId> is ignored: since 0.6.0 Meet reads the acting user from the \" +\n \"Supabase client's own session.\",\n remedy:\n \"Delete the userId prop. Passing a copy of the user id is what let a tab whose auth \" +\n \"cookie had rotated issue reads as an account it could no longer prove it was — the \" +\n \"database refused them at 403 (DD-240).\",\n });\n }, [legacyUserId, report]);\n\n const guestName = guestLaneName(props.guestName);\n // The guest lane reads no session; the member lane reads nothing else.\n const session = useSessionIdentity(guestName === null ? client : null, report);\n const actingUserId = guestName === null ? session.userId : null;\n\n // 🚨 RIDE THE HOST'S REALTIME MANAGER WHEN THERE IS ONE (0.6.5).\n //\n // Through 0.6.4 this ALWAYS mounted a provider of its own, with `client={null}`\n // until an organization was selected. That shadowed the host's manager for\n // everything below Meet: a sibling that rides a mounted host provider (as\n // `@ai-matrx/messaging` does) read a NULL manager forever when no org was\n // selected — `/messages` spun and a thread showed \"0 members\" — and with an\n // org selected it got a SECOND manager (two sockets, two write ledgers).\n // The probe is provider PRESENCE (`@ai-matrx/realtime` 0.3.0), never\n // `useRealtimeManager() !== null`, which is also null while a mounted host\n // provider waits for its client.\n //\n // And the realtime connection never waits on the organization: a socket is\n // the PERSON's (access belongs to the person, 2026-09-23). Whether Meet's own\n // runtime needs an org is MeetRuntime's question, not the transport's.\n const hostProvidesRealtime = useIsRealtimeProviderMounted();\n const runtime = (\n <MeetRuntime\n {...props}\n report={report}\n actingUserId={actingUserId}\n guestLaneName={guestName}\n sessionResolved={guestName !== null || session.state === \"resolved\"}\n />\n );\n if (hostProvidesRealtime) return runtime;\n return (\n <RealtimeProvider\n client={client != null ? (client as never) : null}\n actorId={actingUserId ?? undefined}\n >\n {runtime}\n </RealtimeProvider>\n );\n}\n\ninterface MeetRuntimeProps extends MeetProviderProps {\n readonly report: (event: MeetDiagnostic) => void;\n /** Who the SESSION says is acting. Never a prop from outside the package. */\n readonly actingUserId: UserId | null;\n readonly guestLaneName: string | null;\n readonly sessionResolved: boolean;\n}\n\nfunction MeetRuntime(props: MeetRuntimeProps): ReactNode {\n const { client, actingUserId, guestLaneName: guestName, organizationId, baseUrl, children } =\n props;\n const report = props.report;\n const manager = useRealtimeManager();\n\n // Live refs so callbacks always see the CURRENT render's functions without\n // those functions' identities being part of the runtime's lifetime.\n const incomingRef = useRef(props.onIncomingCall);\n incomingRef.current = props.onIncomingCall;\n const accessTokenRef = useRef(props.accessToken);\n accessTokenRef.current = props.accessToken;\n const driverRef = useRef(props.driverFactory);\n driverRef.current = props.driverFactory;\n\n const displayName =\n props.displayName ?? (typeof guestName === \"string\" ? guestName : \"Guest\");\n\n // 🚨 INERT UNTIL THE SESSION HAS ANSWERED. A runtime built during the\n // `resolving` window would issue its first `pendingInvites` read on behalf of\n // a guess; the whole point of DD-240 is that there is no guess.\n const ready =\n client != null &&\n manager !== null &&\n typeof organizationId === \"string\" &&\n organizationId.length > 0 &&\n props.sessionResolved &&\n (guestName !== null || actingUserId !== null);\n\n const host = useMemo<MeetHost | null>(() => {\n if (!ready || manager === null || client == null) return null;\n\n const identity: MeetIdentity = {\n // THE SESSION'S ANSWER, never a prop (DD-240).\n userId: actingUserId,\n organizationId: asOrganizationId(organizationId as string),\n displayName,\n avatarUrl: props.avatarUrl ?? null,\n deviceId: deviceId(),\n };\n\n const effectsStorage = createWebEffectsStorage();\n // Seeded BEFORE the room: the pre-join screen shows (and previews) the\n // remembered choice, and the engine applies the same one on connect.\n const store = createMeetStore({ effects: effectsStorage.load() });\n const devicesHolder: { current: DeviceManager | null } = { current: null };\n const api = createMeetApi({\n baseUrl,\n organizationId: identity.organizationId,\n accessToken: (...args) => accessTokenRef.current(...args),\n });\n const repository = createMeetRepository({ client });\n // MRF-1: a GUEST's pass is kept on this device so the durable link still\n // opens the record after the meeting — `/token` will not mint another one\n // for a finished meeting, correctly, and a guest has no session to prove\n // they were here with. `createTokenClient` stores only guest passes.\n const tokens = createTokenClient({\n api,\n storage: createWebRoomTokenStorage((message, remedy) =>\n report({ level: \"warn\", message, remedy }),\n ),\n });\n const engine = createRoomEngine({\n store,\n tokens,\n identity,\n resolveMeeting: (slug) => repository.meetingBySlug(slug),\n driverFactory: (handlers) =>\n (driverRef.current ?? createLiveKitDriver)(handlers),\n onDiagnostic: report,\n effectsStorage,\n resolveDevice: (kind) => devicesHolder.current?.resolve(kind) ?? null,\n });\n const meetings = createMeetingSession({\n manager,\n repository,\n store,\n identity,\n api,\n onDiagnostic: report,\n // ADMISSION IS A JOIN, NOT A RE-RENDER. The lobby token grants neither\n // publish nor subscribe, so the host saying yes has to mint a new one.\n onAdmitted: () => {\n void engine.rejoin();\n },\n // A \"no\" is ALSO a mint: the server refuses it with its own sentence, which\n // turns the waiting room into the pre-join screen showing that sentence.\n onDenied: () => {\n void engine.rejoin().catch(() => undefined);\n },\n });\n // THE AI IS PART OF THE RUNTIME, not an optional attachment. Nothing here\n // names an agent: every capability is a server-owned Mandate (D2).\n const resolveRoomToken = (): string | null => {\n const roomName = store.snapshot().meeting?.roomName;\n if (roomName === undefined) return null;\n const active = engine.token();\n if (active?.roomName === roomName && active.token.length > 0) return active.token;\n return tokens.remembered(roomName)?.token ?? null;\n };\n const ai = createMeetAi({ api, store, resolveRoomToken });\n const inRoom = createInRoomClient({ api, store, resolveRoomToken });\n // THE SAVED CHAT IS READ ON EVERY JOIN (Meet wave 2) — that is what makes a\n // late joiner see what was already said. Once per connected room; a refusal\n // is a diagnostic with a remedy, and live messages keep arriving regardless.\n let chatReadFor: string | null = null;\n store.subscribe(() => {\n const snapshot = store.snapshot();\n if (snapshot.phase !== \"connected\" || snapshot.meeting === null) {\n if (snapshot.phase === \"left\" || snapshot.phase === \"idle\") chatReadFor = null;\n return;\n }\n if (chatReadFor === snapshot.meeting.id) return;\n chatReadFor = snapshot.meeting.id;\n void inRoom.loadChat().catch((error: unknown) => {\n const normalized = error as { message?: string; remedy?: string };\n // NEVER \"Reading…\" FOREVER: the panel says history is unavailable, and why.\n store.patch({\n chatLoaded: true,\n chatHistoryError:\n normalized.remedy ?? \"Messages sent before you joined could not be read. New messages still arrive.\",\n });\n report({\n level: \"warn\",\n message: normalized.message ?? \"meet: the saved chat could not be read\",\n ...(normalized.remedy !== undefined ? { remedy: normalized.remedy } : {}),\n });\n });\n });\n const recording = createRecordingController({\n api,\n store,\n acknowledgeConsent: async (meetingId) => {\n await repository.recordConsent({\n meetingId,\n identity: store.snapshot().localIdentity ?? identity.deviceId,\n acknowledgedAt: new Date().toISOString(),\n });\n },\n });\n const devices = createDeviceManager({\n media: (globalThis as unknown as { navigator?: { mediaDevices?: MediaDevicesLike } })\n .navigator?.mediaDevices ?? {\n // An SSR render or a browser without media devices gets an INERT\n // manager that reports the truth, rather than a crash on import.\n enumerateDevices: async () => [],\n getUserMedia: async () => ({ getTracks: () => [] }),\n },\n storage: createWebDeviceStorage(),\n });\n devicesHolder.current = devices;\n // A GUEST HAS NO CALLING SURFACE. Not \"a disabled one\" — none at all, so\n // there is nothing to render as a dead button (D6, no dead ends).\n const calls =\n identity.userId === null\n ? null\n : createCallCenter({\n manager,\n repository,\n store,\n identity,\n onIncoming: (invite) => incomingRef.current?.(invite),\n onDiagnostic: report,\n ...(props.ringTimeoutMs !== undefined ? { ringTimeoutMs: props.ringTimeoutMs } : {}),\n });\n\n return {\n store,\n engine,\n calls,\n meetings,\n inRoom,\n recording,\n devices,\n repository,\n tokens,\n ai,\n api,\n identity,\n baseUrl,\n accessToken: (...args) => accessTokenRef.current(...args),\n report,\n };\n // 🚨 IDENTITY ONLY. See the header: adding callbacks or option objects here\n // rebuilds every channel — and drops the call in progress — on every render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n ready,\n manager,\n client,\n actingUserId,\n guestName,\n organizationId,\n baseUrl,\n displayName,\n report,\n ]);\n\n useEffect(() => {\n if (host?.calls == null) return undefined;\n const center = host.calls;\n void center.start().catch((error: unknown) => {\n host.report({\n level: \"error\",\n message: `Meet could not start listening for calls: ${String(\n (error as Error)?.message ?? error,\n )}`,\n remedy:\n \"Calls will not ring on this device until this succeeds. Check the session and \" +\n \"organization, then reload the surface.\",\n });\n });\n return () => {\n center.dispose();\n };\n }, [host]);\n\n useEffect(() => {\n if (host === null) return undefined;\n return () => {\n host.meetings.dispose();\n host.devices.dispose();\n void host.engine.dispose();\n };\n }, [host]);\n\n return <MeetContext.Provider value={host}>{children}</MeetContext.Provider>;\n}\n\n/** The host, or `null` while auth/org are still resolving. */\nexport function useMeetHost(): MeetHost | null {\n return useContext(MeetContext);\n}\n\nexport function useRequiredMeetHost(): MeetHost {\n const host = useMeetHost();\n if (host === null) {\n throw new Error(\n \"[@ai-matrx/meet] No meet host. Wrap this tree in <MeetProvider client={supabase} \" +\n \"baseUrl={aidreamUrl} organizationId={orgId} accessToken={fn}> and render it only \" +\n \"once auth has resolved.\",\n );\n }\n return host;\n}\n\n/** The whole room snapshot, re-rendering only when it actually changes. */\nexport function useMeetSnapshot(): MeetSnapshot | null {\n const host = useMeetHost();\n const store = host?.store ?? null;\n const empty = useRef<MeetSnapshot | null>(null);\n return useSyncExternalStore(\n (listener) => (store === null ? () => undefined : store.subscribe(listener)),\n () => (store === null ? empty.current : store.snapshot()),\n () => (store === null ? empty.current : store.snapshot()),\n );\n}\n\nexport function useDeviceSnapshot(): DeviceSnapshot | null {\n const host = useMeetHost();\n const devices = host?.devices ?? null;\n return useSyncExternalStore(\n (listener) => (devices === null ? () => undefined : devices.subscribe(() => listener())),\n () => devices?.snapshot() ?? null,\n () => devices?.snapshot() ?? null,\n );\n}\n\n/**\n * 🚨 THE LOCAL PARTICIPANT'S ROLE — THE SERVER'S WORD, FROM BOTH ITS CARRIERS\n * (MRI-A11, feedback `7418ef78`).\n *\n * Two sources, one decision made once in `services/meet/service.py`:\n *\n * 1. `snapshot.grants.role` — the `/meet/token` response, in the store from the\n * instant the token lands, which is BEFORE any LiveKit roster exists.\n * 2. the local participant's roster entry, whose role comes from the\n * `matrx.participant.role` LiveKit attribute the same mint published.\n *\n * The stronger of the two wins, and both are server-minted, so this can never\n * be client state: there is no branch here a browser could take on its own.\n * Reading only (2) is the shipped defect this replaces — a roster entry arrives\n * a beat later than the token and, before MRI-A11, carried no role at all.\n */\nexport function useRole(): ParticipantRole {\n const snapshot = useMeetSnapshot();\n // ONE definition, shared with the code that PERFORMS the host actions\n // (`core/store.ts`). A second copy here is how the UI and the action drift.\n return snapshot === null ? \"participant\" : effectiveRole(snapshot);\n}\n\n/** Does the local participant hold host powers? ONE predicate, one definition. */\nexport function useIsHost(): boolean {\n return isHostRole(useRole());\n}\n\n/**\n * May the local participant start a recording? NOT `isHost` — the meeting's\n * recording policy is the server's, and an `always-on` meeting is recorded by\n * the server with no host control at all (MRI-A11).\n */\nexport function useCanRecord(): boolean {\n const snapshot = useMeetSnapshot();\n if (snapshot === null) return false;\n const me = snapshot.participants.find(\n (participant) => participant.identity === snapshot.localIdentity,\n );\n return snapshot.grants.canRecord || me?.canRecord === true;\n}\n\nexport function useLocalUserId(): UserId | null {\n return useMeetHost()?.identity.userId ?? null;\n}\n","/**\n * AI-NATIVE, ON BY DEFAULT — and SERVER-OWNED as of 0.3.0 (R4, D2, D16).\n *\n * 🚨 **THE PACKAGE NO LONGER KNOWS WHO ANSWERS.** Through 0.2.1 a host injected\n * `MeetAgents` — four database row ids — and this module ran the agent itself,\n * shipping the transcript up as `variables`. Both halves of that are gone:\n *\n * 1. **No agent id crosses this boundary, and none is injected.** Reasoning runs\n * behind Mandates whose Holder is resolved from the database at run time\n * (`meet.live_notes`, `meet.live_intelligence`, `meet.wrap_up`), so an\n * organization rebinds the job in the Mandate admin with no release of this\n * package and no change in the host. A host that had to supply an id was a\n * host that could supply the WRONG id, and a capability that silently\n * disappeared when nobody had filled a config line.\n * 2. **No transcript crosses this boundary either.** `POST /v1/meet/intelligence/ask`\n * takes `{meeting_id, question}` and NOTHING else; the answer is built\n * server-side from durable rows. Captions are hints and this client holds\n * only hints (D16) — sending them would be sending the model our guesses.\n *\n * What is left here is small and honest: ask a question and render the answer\n * as it streams, summon or dismiss the note-taker, end the meeting for\n * everyone, and report the server's refusal in the server's own words.\n *\n * 🚨 **THE USER-INPUT LAW still holds** and is now the server's to keep:\n * `question` is the one genuine human utterance in this module, and it is the\n * only free text this package sends anywhere near a model.\n */\n\nimport { readMatrxNdjsonStream } from \"@ai-matrx/agents\";\nimport type { MeetApi } from \"./api\";\nimport { MeetError } from \"./errors\";\nimport type { NoteTakerRefusal } from \"./note-taker\";\nimport type { MeetStore } from \"./store\";\nimport { MEET_ROUTES, ROOM_TOKEN_HEADER } from \"./tokens\";\nimport type { MeetingId, RoomName } from \"./types\";\n\nexport interface MeetAiOptions {\n /** The ONE org-aware aidream client (MRI-A16). Owns base url and headers. */\n api: MeetApi;\n store: MeetStore;\n /**\n * Resolves the current meeting's room pass for a guest Q&A request. The\n * provider owns this because it alone has both the active room and its\n * persisted guest pass. `null` leaves the header absent for signed-in record\n * Q&A, where the session remains the credential.\n */\n resolveRoomToken?: (() => string | null) | undefined;\n}\n\n/** What the answer was built from. The server measures it; we never guess it. */\nexport interface MeetAnswerCoverage {\n readonly segmentsUsed: number;\n readonly segmentsTotal: number;\n readonly truncated: boolean;\n readonly speakers: readonly string[];\n}\n\nexport interface MeetAiAnswer {\n readonly text: string;\n readonly coverage: MeetAnswerCoverage | null;\n}\n\nexport interface AskArgs {\n readonly meetingId: MeetingId;\n readonly question: string;\n readonly signal?: AbortSignal | undefined;\n /** Called with the answer so far, every time it grows. Rendering is live. */\n readonly onText?: ((text: string) => void) | undefined;\n /** The server's phase, verbatim, so a slow answer is never a bare spinner. */\n readonly onPhase?: ((phase: string) => void) | undefined;\n}\n\nexport interface NoteTakerDispatch {\n readonly dispatched: boolean;\n /** The server's sentence. Never empty on a refusal. */\n readonly detail: string;\n}\n\nexport interface MeetAi {\n /** In-meeting Q&A. The ONE human utterance this package sends (D16). */\n ask(args: AskArgs): Promise<MeetAiAnswer>;\n /** Ask aidream to dispatch the note-taker INTO the room. Host-only. */\n startNoteTaker(args: { meetingId: MeetingId; roomName: RoomName }): Promise<NoteTakerDispatch>;\n /** Dismiss it. Nothing automatic brings a dismissed note-taker back (D9). */\n stopNoteTaker(args: { meetingId: MeetingId }): Promise<NoteTakerDispatch>;\n}\n\n/** The event vocabulary `/intelligence/ask` emits, pinned by the server's FEATURE.md. */\nexport const MEET_ANSWER_EVENTS = {\n chunk: \"chunk\",\n info: \"info\",\n phase: \"phase\",\n error: \"error\",\n end: \"end\",\n} as const;\n\n/** The `info` event carrying what the answer was built from. */\nexport const MEET_ANSWER_CONTEXT_EVENT = \"meet_intelligence_context\";\n\n/**\n * The coverage numbers, wherever the canonical emitter put them.\n *\n * 🚨 THE LIVE WIRE NESTS THEM UNDER `metadata`. `InfoPayload` is\n * `{code, system_message, user_message, metadata}`, so the numbers arrive at\n * `data.metadata.segments_used` — not at `data.segments_used`, which is what\n * this function read until it was walked against the real route on 2026-09-08\n * and quietly reported no coverage at all. Every shape is read now, and the\n * fixture in `ai.test.ts` is a VERBATIM line off the production stream.\n */\nfunction readCoverage(data: unknown): MeetAnswerCoverage | null {\n if (typeof data !== \"object\" || data === null) return null;\n const row = data as Record<string, unknown>;\n const candidates: Record<string, unknown>[] = [row];\n for (const key of [\"metadata\", \"data\"]) {\n const nested = row[key];\n if (typeof nested === \"object\" && nested !== null && !Array.isArray(nested)) {\n candidates.push(nested as Record<string, unknown>);\n }\n }\n const source =\n candidates.find(\n (entry) =>\n typeof entry[\"segments_used\"] === \"number\" ||\n typeof entry[\"segments_total\"] === \"number\",\n ) ?? null;\n if (source === null) return null;\n const used = source[\"segments_used\"];\n const total = source[\"segments_total\"];\n const speakers = source[\"speakers\"];\n return {\n segmentsUsed: typeof used === \"number\" ? used : 0,\n segmentsTotal: typeof total === \"number\" ? total : 0,\n truncated: source[\"transcript_truncated\"] === true,\n speakers: Array.isArray(speakers)\n ? speakers.filter((entry): entry is string => typeof entry === \"string\")\n : [],\n };\n}\n\nfunction readText(data: unknown): string {\n if (typeof data === \"string\") return data;\n if (typeof data !== \"object\" || data === null) return \"\";\n const row = data as Record<string, unknown>;\n // `phase` and `system_message` are on this list because the live emitter\n // sends `{\"phase\":\"generating\"}` and `{\"system_message\":\"Reading the meeting\n // transcript\"}`. Without them a phase rendered as \"[object Object]\" —\n // found by walking the real route, not by any test written from the docs.\n for (const key of [\"text\", \"content\", \"delta\", \"t\", \"phase\", \"system_message\"]) {\n const value = row[key];\n if (typeof value === \"string\") return value;\n }\n return \"\";\n}\n\ninterface ServerRefusal {\n readonly reason: string;\n readonly remedy: string;\n}\n\n/**\n * THE SERVER'S REFUSAL, READ RATHER THAN RE-WRITTEN.\n *\n * aidream answers a refused dispatch with a body carrying its own `reason` and\n * `remedy` — \"no worker is registered under matrx-note-taker\", and what to do\n * about it. FastAPI nests a raised `HTTPException` under `detail`, and a\n * validation failure produces a list. All three shapes are read here so the\n * screen shows the system's own words instead of \"something went wrong\".\n */\nexport function readServerRefusal(body: unknown): ServerRefusal | null {\n if (typeof body === \"string\") {\n return body.trim().length === 0 ? null : { reason: body.trim(), remedy: \"\" };\n }\n if (typeof body !== \"object\" || body === null) return null;\n const row = body as Record<string, unknown>;\n const detail = row[\"detail\"];\n if (Array.isArray(detail)) {\n // FastAPI's validation shape: `{msg, loc}`. The FIELD is in `loc` and the\n // field is the whole point — \"Field required\" alone names nothing.\n const messages = detail\n .map((entry) => {\n if (typeof entry !== \"object\" || entry === null) return String(entry);\n const row = entry as Record<string, unknown>;\n const message = String(row[\"msg\"] ?? \"\");\n const where = Array.isArray(row[\"loc\"])\n ? row[\"loc\"].filter((part): part is string => typeof part === \"string\").join(\".\")\n : \"\";\n return where.length > 0 ? `${message} (${where})` : message;\n })\n .filter((entry) => entry.length > 0);\n return messages.length === 0 ? null : { reason: messages.join(\"; \"), remedy: \"\" };\n }\n if (typeof detail === \"object\" && detail !== null) return readServerRefusal(detail);\n const reason =\n typeof row[\"reason\"] === \"string\"\n ? row[\"reason\"]\n : typeof row[\"message\"] === \"string\"\n ? row[\"message\"]\n : typeof detail === \"string\"\n ? detail\n : typeof row[\"error\"] === \"string\"\n ? row[\"error\"]\n : null;\n if (reason === null) return null;\n const remedy = typeof row[\"remedy\"] === \"string\" ? row[\"remedy\"] : \"\";\n if (remedy.length > 0) return { reason, remedy };\n // THE SERVER WRITES ITS REMEDY INLINE. Meet's own errors read\n // \"<what happened>. Fix: <what to do>.\" — splitting it here is what puts the\n // fix on its own line in the panel instead of burying it mid-paragraph.\n const fix = reason.indexOf(\"Fix:\");\n if (fix > 0) {\n return {\n reason: reason.slice(0, fix).trim(),\n remedy: reason.slice(fix + \"Fix:\".length).trim(),\n };\n }\n return { reason, remedy };\n}\n\nexport function createMeetAi(options: MeetAiOptions): MeetAi {\n /**\n * Every request here goes through the ONE org-aware client (MRI-A16), which\n * puts `x-organization-id` on it — the 0.1.3 lesson, now structural rather\n * than remembered. A refused session is translated into THIS surface's own\n * sentence, because \"sign in\" means something specific for the note-taker.\n */\n async function send(input: {\n path: string;\n body: Record<string, unknown>;\n operation: string;\n requireAuth: boolean;\n headers?: Record<string, string> | undefined;\n signal?: AbortSignal | undefined;\n }): Promise<Response> {\n try {\n return await options.api.request({\n path: input.path,\n method: \"POST\",\n requireAuth: input.requireAuth,\n operation: input.operation,\n body: input.body,\n ...(input.headers !== undefined ? { headers: input.headers } : {}),\n ...(input.signal !== undefined ? { signal: input.signal } : {}),\n });\n } catch (error) {\n if ((error as { code?: string }).code === \"session-unavailable\") {\n throw new MeetError(\n \"forbidden\",\n `${input.operation}: this action needs a signed-in host`,\n \"A guest cannot summon or dismiss the note-taker, and the control is hidden for \" +\n \"them. Sign in as the meeting's host to use it.\",\n );\n }\n throw error;\n }\n }\n\n async function refusalFor(response: Response, operation: string): Promise<NoteTakerRefusal> {\n let body: unknown = null;\n try {\n body = await response.json();\n } catch {\n try {\n body = await response.text();\n } catch {\n body = null;\n }\n }\n const parsed = readServerRefusal(body);\n // 🚨 A NAMED SERVER GAP, ANNOUNCED RATHER THAN PAPERED OVER. 0.3.0 stopped\n // sending `agent_id` because which agent transcribes is the server's\n // business (D2), but aidream's `NoteTakerStartRequest` still DECLARES that\n // field, so a server that has not landed the MRI-A2 side answers FastAPI's\n // validation error — which reads like a client bug to the person clicking.\n // This translates it into what is actually true. It never invents an id.\n if (response.status === 422 && (parsed?.reason ?? \"\").includes(\"agent_id\")) {\n return {\n status: 422,\n reason:\n \"This server still expects the caller to name the note-taker agent, and this \" +\n \"version of @ai-matrx/meet deliberately does not.\",\n remedy:\n \"The note-taker's identity is a Mandate binding the server resolves (D2). Update \" +\n \"aidream so `/v1/meet/agent/start` resolves the agent itself — register item \" +\n \"MRI-A2/A6. Until then the note-taker cannot be summoned from this surface, and \" +\n \"nothing about this meeting is being transcribed.\",\n };\n }\n return {\n status: response.status,\n reason:\n parsed?.reason ??\n `${operation}: the server answered ${response.status} with no reason.`,\n remedy:\n parsed?.remedy !== undefined && parsed.remedy.length > 0\n ? parsed.remedy\n : \"The server refused and said nothing more. The meeting continues WITHOUT the \" +\n \"note-taker and this surface says so — a silent failure here is a meeting \" +\n \"everyone believes is being minuted.\",\n };\n }\n\n async function dispatch(\n route: string,\n body: Record<string, unknown>,\n operation: string,\n ): Promise<NoteTakerDispatch> {\n // The session check happens BEFORE the request, so a guest's refusal is a\n // package sentence rather than a round trip the server would reject anyway.\n const response = await send({ path: route, body, operation, requireAuth: true });\n if (!response.ok) {\n const refusal = await refusalFor(response, operation);\n // THE REFUSAL IS STATE, not only an exception: every surface renders the\n // server's sentence until the next attempt, rather than a control that\n // looks like it did nothing.\n options.store.patch({ noteTakerRefusal: refusal });\n throw new MeetError(\n response.status === 403 ? \"forbidden\" : \"transport\",\n refusal.reason,\n refusal.remedy,\n );\n }\n options.store.patch({ noteTakerRefusal: null });\n let payload: unknown = null;\n try {\n payload = await response.json();\n } catch {\n payload = null;\n }\n const row =\n typeof payload === \"object\" && payload !== null\n ? (payload as Record<string, unknown>)\n : {};\n return {\n dispatched: row[\"dispatched\"] === true,\n detail: typeof row[\"detail\"] === \"string\" ? row[\"detail\"] : \"\",\n };\n }\n\n return {\n async ask({ meetingId, question, signal, onText, onPhase }) {\n const trimmed = question.trim();\n if (trimmed.length === 0) {\n throw new MeetError(\n \"misconfigured\",\n \"meet.ai.ask: an empty question\",\n \"Type a question. Nothing is sent until there is one.\",\n );\n }\n const roomToken = options.resolveRoomToken?.() ?? null;\n const response = await send({\n path: MEET_ROUTES.intelligenceAsk,\n // THE WHOLE BODY. No transcript, no context, no agent id (D16).\n body: { meeting_id: meetingId, question: trimmed },\n operation: \"meet.ai.ask\",\n // A GUEST MAY ASK. The server decides whether it can answer.\n requireAuth: false,\n ...(roomToken !== null ? { headers: { [ROOM_TOKEN_HEADER]: roomToken } } : {}),\n ...(signal !== undefined ? { signal } : {}),\n });\n if (!response.ok) {\n // Both refusals happen BEFORE the stream opens, by the server's design,\n // so this is an honest status rather than a stream that dies mid-answer.\n const refusal = await refusalFor(response, \"meet.ai.ask\");\n throw new MeetError(\n response.status === 403 || response.status === 401\n ? \"forbidden\"\n : response.status === 404\n ? \"not-found\"\n : \"transport\",\n refusal.reason,\n refusal.remedy,\n );\n }\n const body = response.body;\n if (body === null || body === undefined) {\n throw new MeetError(\n \"invalid-response\",\n \"meet.ai.ask: the answer arrived with no stream to read\",\n \"The route streams NDJSON. A response with no body means a proxy buffered or \" +\n \"stripped it — check for a gateway that does not pass streaming responses.\",\n );\n }\n let text = \"\";\n let coverage: MeetAnswerCoverage | null = null;\n let failure: ServerRefusal | null = null;\n for await (const envelope of readMatrxNdjsonStream(\n body,\n signal !== undefined ? { signal } : {},\n )) {\n if (envelope.event === MEET_ANSWER_EVENTS.chunk) {\n const piece = readText(envelope.data);\n if (piece.length > 0) {\n // THE ANSWER IS THE CONCATENATED CHUNKS — the server deliberately\n // sends no second copy in a terminal payload, so this accumulation\n // IS the answer, not an optimization.\n text += piece;\n onText?.(text);\n }\n continue;\n }\n if (envelope.event === MEET_ANSWER_EVENTS.info) {\n const parsed = readCoverage(envelope.data);\n if (parsed !== null) coverage = parsed;\n continue;\n }\n if (envelope.event === MEET_ANSWER_EVENTS.phase) {\n const phase = readText(envelope.data);\n onPhase?.(phase.length > 0 ? phase : String(envelope.data));\n continue;\n }\n if (envelope.event === MEET_ANSWER_EVENTS.error) {\n failure = readServerRefusal(envelope.data);\n }\n }\n if (failure !== null) {\n throw new MeetError(\n \"transport\",\n failure.reason,\n failure.remedy.length > 0\n ? failure.remedy\n : \"The answer stopped mid-stream and the server said why. Ask again once the \" +\n \"named cause is cleared.\",\n );\n }\n if (text.trim().length === 0) {\n throw new MeetError(\n \"invalid-response\",\n \"meet.ai.ask: the stream ended with no answer in it\",\n \"Nothing was returned to show. Check the meeting has a Holder bound to \" +\n \"`meet.live_intelligence` at /mandates, then ask again.\",\n );\n }\n return { text: text.trim(), coverage };\n },\n\n startNoteTaker: ({ meetingId, roomName }) =>\n dispatch(\n MEET_ROUTES.noteTakerStart,\n {\n // NO agent_id. Which agent transcribes is the server's business\n // (D2) — this package could not name one if it wanted to.\n meeting_id: meetingId,\n room_name: roomName,\n organization_id: options.api.organizationId,\n },\n \"meet.ai.startNoteTaker\",\n ),\n\n stopNoteTaker: ({ meetingId }) =>\n dispatch(\n MEET_ROUTES.noteTakerStop,\n { meeting_id: meetingId },\n \"meet.ai.stopNoteTaker\",\n ),\n };\n}\n","/**\n * ONE error classification for the whole package (C22).\n *\n * The banned alternative is a host catching a LiveKit or PostgREST error and\n * deciding for itself whether the camera is busy, the token expired, or the\n * meeting is locked — which is how the same five-branch `if` gets copy-pasted\n * into every consumer and drifts. Everything this package throws is a\n * `MeetError` with a stable `code` and a `remedy` SENTENCE. Nothing fails\n * silently, and nothing fails without saying what to do about it.\n *\n * The device codes exist because \"it doesn't work\" in a video product is almost\n * always one of four specific, differently-remediable things: permission\n * denied, no such device, device already in use by another app, or insecure\n * context (http, where `getUserMedia` does not exist at all). A single\n * \"media-error\" would make the UI say the wrong sentence three times out of\n * four.\n */\n\nexport type MeetErrorCode =\n | \"session-unavailable\"\n | \"forbidden\"\n | \"not-found\"\n | \"conflict\"\n | \"token\"\n | \"transport\"\n | \"invalid-response\"\n | \"misconfigured\"\n | \"permission-denied\"\n | \"device-not-found\"\n | \"device-in-use\"\n | \"insecure-context\"\n | \"media-unsupported\"\n | \"room-locked\"\n | \"lobby-denied\"\n | \"capacity\"\n /** Meet wave 1: the meeting was cancelled — its link resolves, its room never opens. */\n | \"cancelled\"\n | \"unknown\";\n\nexport class MeetError extends Error {\n readonly code: MeetErrorCode;\n /** What to DO. Rendered to the user for the device codes. */\n readonly remedy: string;\n override readonly cause?: unknown;\n\n constructor(code: MeetErrorCode, message: string, remedy: string, cause?: unknown) {\n super(message);\n this.name = \"MeetError\";\n this.code = code;\n this.remedy = remedy;\n if (cause !== undefined) this.cause = cause;\n }\n\n /** True when retrying after the host re-establishes a session is the fix. */\n get isRetryable(): boolean {\n return (\n this.code === \"session-unavailable\" ||\n this.code === \"transport\" ||\n this.code === \"token\"\n );\n }\n\n /** True when the user, not the code, must act — the UI shows `remedy`. */\n get isUserActionable(): boolean {\n return (\n this.code === \"permission-denied\" ||\n this.code === \"device-not-found\" ||\n this.code === \"device-in-use\" ||\n this.code === \"insecure-context\"\n );\n }\n}\n\ninterface ErrorLike {\n name?: string | undefined;\n message?: string | undefined;\n code?: string | undefined;\n}\n\nconst FORBIDDEN_CODES = new Set([\"42501\", \"PGRST301\", \"PGRST302\"]);\nconst NOT_FOUND_CODES = new Set([\"PGRST116\", \"PGRST205\"]);\n// 40001: the row changed since the caller read it (meet_update_meeting's version\n// compare-and-swap). 55000: the object is in a state that refuses the change (a\n// cancelled meeting). Both are conflicts a person resolves by reloading.\nconst CONFLICT_CODES = new Set([\"23505\", \"40001\", \"55000\"]);\n\nconst SESSION_MARKERS = [\n \"auth session missing\",\n \"jwt expired\",\n \"no api key found\",\n \"refresh_token_not_found\",\n \"invalid claim: missing sub claim\",\n];\n\n/**\n * THE ONE PLACE a raw database/transport error becomes a typed one. Called at\n * every repository boundary; nothing else in the package inspects a raw error,\n * and no consumer should ever have to.\n */\nexport function normalizeMeetError(error: unknown, operation: string): MeetError {\n if (error instanceof MeetError) return error;\n\n const raw = (error ?? {}) as ErrorLike;\n const message = typeof raw.message === \"string\" ? raw.message : String(error);\n const code = typeof raw.code === \"string\" ? raw.code : undefined;\n const lowered = message.toLowerCase();\n\n if (raw.name === \"SessionUnavailableError\" || SESSION_MARKERS.some((m) => lowered.includes(m))) {\n return new MeetError(\n \"session-unavailable\",\n `${operation}: no Supabase session available (${message})`,\n \"Normal during sign-in and token refresh. The package retries once after the host's \" +\n \"session source resolves; log it as a warning, never as an error.\",\n error,\n );\n }\n if (code !== undefined && FORBIDDEN_CODES.has(code)) {\n return new MeetError(\n \"forbidden\",\n `${operation}: denied by the database (${code}: ${message})`,\n \"Authorization is RLS plus auth-checked RPCs (R5). Fix the policy or the caller's \" +\n \"membership — never route around it with a service-role client in a browser.\",\n error,\n );\n }\n if (code !== undefined && NOT_FOUND_CODES.has(code)) {\n return new MeetError(\n \"not-found\",\n `${operation}: not found (${code}: ${message})`,\n \"The row is gone, or RLS hides it. If this is PGRST205 the communication.meet_* tables \" +\n \"are not deployed yet — see MEET_SCHEMA in repository.ts for the exact contract.\",\n error,\n );\n }\n if (code !== undefined && CONFLICT_CODES.has(code)) {\n return new MeetError(\n \"conflict\",\n `${operation}: unique violation (${code}: ${message})`,\n \"A concurrent writer won. Re-read the meeting rather than retrying the insert — for a \" +\n \"call invite this is the idempotency key doing its job.\",\n error,\n );\n }\n return new MeetError(\n \"transport\",\n `${operation}: ${message}`,\n \"Transient transport failure. Reads retry once; a join failure surfaces to the room \" +\n \"phase as `failed` with this message rather than hanging on a spinner.\",\n error,\n );\n}\n\n/**\n * THE DEVICE ERROR TRANSLATOR — the second-most-copied block in every video app.\n *\n * `getUserMedia` rejects with DOMException names, and every one of them means\n * something a user could fix if we told them. This is the whole reason the\n * device layer lives in the package (C22 test 3: less-than-perfect unless done\n * perfectly).\n */\nexport function normalizeDeviceError(error: unknown, operation: string): MeetError {\n if (error instanceof MeetError) return error;\n const raw = (error ?? {}) as ErrorLike;\n const name = raw.name ?? \"\";\n const message = typeof raw.message === \"string\" ? raw.message : String(error);\n\n switch (name) {\n case \"NotAllowedError\":\n case \"SecurityError\":\n return new MeetError(\n \"permission-denied\",\n `${operation}: camera/microphone permission denied`,\n \"Allow camera and microphone access for this site, then rejoin. On macOS also check \" +\n \"System Settings › Privacy & Security — a browser denied there shows the same error.\",\n error,\n );\n case \"NotFoundError\":\n case \"OverconstrainedError\":\n return new MeetError(\n \"device-not-found\",\n `${operation}: no matching camera/microphone (${message})`,\n \"The selected device is gone — usually an unplugged headset. Pick another device in \" +\n \"the pre-join panel; the package falls back to the system default automatically.\",\n error,\n );\n case \"NotReadableError\":\n case \"AbortError\":\n return new MeetError(\n \"device-in-use\",\n `${operation}: the device is already in use (${message})`,\n \"Another application (or another tab) holds the camera. Close it and try again — the \" +\n \"hardware, not the meeting, is what refused.\",\n error,\n );\n case \"TypeError\":\n return new MeetError(\n \"insecure-context\",\n `${operation}: media devices are unavailable in this context (${message})`,\n \"getUserMedia only exists on https or localhost. Serve the app over https.\",\n error,\n );\n default:\n return new MeetError(\n \"media-unsupported\",\n `${operation}: ${message}`,\n \"This browser refused the media request for a reason the package does not recognize. \" +\n \"Report it with this message so the class gets a named remedy rather than a shrug.\",\n error,\n );\n }\n}\n\n/** A response whose SHAPE is wrong — the ingress boundary, not the wire. */\nexport function invalidResponse(operation: string, detail: string): MeetError {\n return new MeetError(\n \"invalid-response\",\n `${operation}: ${detail}`,\n \"The server returned a shape this package does not accept. Rendering it would put a lie \" +\n \"on the screen, so it is refused here. Fix the endpoint's return contract.\",\n );\n}\n","/**\n * THE TOKEN FLOW — the ONLY authorization path into a room (R1).\n *\n * 🚨 **THE CLIENT NEVER HOLDS A LIVEKIT SECRET.** Not in an env var, not in a\n * build-time constant, not \"just for local dev\". A LiveKit API secret in a\n * browser bundle mints a token for ANY room in the project, including one the\n * holder was never invited to — it is a full compromise of every meeting in the\n * organization. This package therefore has no code path that could accept one:\n * it asks aidream, and aidream mints.\n *\n * Four hard parts live here so no host reimplements them (C22):\n *\n * 1. **Single flight.** A React strict-mode double effect, a re-render, and a\n * reconnect all ask at once; they share ONE request. Two tokens for one\n * identity is not harmless — LiveKit disconnects the older session, which\n * looks exactly like \"my call randomly drops when I open the tab\".\n * 2. **Expiry is honored BEFORE it bites.** A token is refreshed at 80% of its\n * life, not when a reconnect fails at 100%. A meeting that outlives its\n * token and cannot reconnect is the classic 2-hour-meeting bug.\n * 3. **Guests are first-class, not an exception.** A guest has no session and\n * the request carries a display name instead; the SERVER decides what a\n * guest may do. There is no client-side \"is this person allowed\" branch.\n * 4. **A missing session is a lifecycle moment.** Between sign-in and token\n * arrival, the fetch retries ONCE after the host's session resolves and then\n * reports `session-unavailable` as a warning — never a red error, never a\n * retry storm.\n */\n\nimport type { MeetApi } from \"./api\";\nimport { invalidResponse, MeetError } from \"./errors\";\nimport type {\n MeetIdentity,\n ParticipantIdentity,\n ParticipantRole,\n RoomName,\n} from \"./types\";\n\nexport interface RoomToken {\n readonly token: string;\n readonly serverUrl: string;\n readonly roomName: RoomName;\n readonly identity: ParticipantIdentity;\n readonly displayName: string;\n /** ISO. The package refreshes at 80% of the remaining life. */\n readonly expiresAt: string;\n /** What the SERVER granted. The client renders from this; it never decides. */\n readonly canPublish: boolean;\n readonly canSubscribe: boolean;\n readonly canRecord: boolean;\n readonly isHost: boolean;\n /**\n * 🚨 THE SERVER'S WORD ON WHO THIS JOINER IS (MRI-A11) — `host`,\n * `participant` or `guest`, minted from `host_user_id` or a real iam grant.\n * The same string is minted into the LiveKit token's participant metadata and\n * its `matrx.participant.role` attribute, so the roster and this response\n * cannot disagree. A server that predates MRI-A11 sends no role, and the\n * fallback below reads the older `is_host` boolean rather than pretending.\n */\n readonly role: ParticipantRole;\n /** True when the server put this joiner in the lobby (D6). */\n readonly lobby: boolean;\n}\n\nexport type { AccessTokenSource } from \"./api\";\n\nexport interface TokenClientOptions {\n /** The ONE org-aware aidream client (MRI-A16). Owns base url and headers. */\n api: MeetApi;\n /** Injected clock, so expiry logic is provable without waiting two hours. */\n now?: (() => number) | undefined;\n /**\n * Where a GUEST's pass survives a page close (MRF-1). Absent means passes\n * live only in memory, which is correct for a member (they have a session to\n * mint a new one from) and is why this is optional rather than assumed.\n */\n storage?: RoomTokenStorage | undefined;\n}\n\n/**\n * 🚨 **WHY A GUEST'S PASS MUST OUTLIVE THE TAB (MRF-1).**\n *\n * A guest has no session, so their only credential for a meeting is the room\n * token this server minted for them. After the meeting ends, `/token` refuses\n * to mint another one — correctly: the room is gone and nobody may rejoin it.\n * So a guest who closes the tab and comes back to read the summary has, in a\n * purely in-memory client, *no way to prove they were ever there* — and the one\n * honest thing left to show them is a refusal.\n *\n * Persisting the pass is what makes the durable link durable for them. It is\n * per-device by nature (it is stored beside the device id that minted it) and\n * it expires on its own: `meet.room_token_ttl_seconds` is the organization's\n * setting for how long, and an expired pass produces the renew-the-link\n * sentence, never \"you were never here\".\n */\nexport interface RoomTokenStorage {\n read(roomName: RoomName): string | null;\n write(roomName: RoomName, serialized: string): void;\n remove(roomName: RoomName): void;\n}\n\n/** `localStorage` when it exists; a no-op that SAYS so otherwise. */\nexport function createWebRoomTokenStorage(\n onDiagnostic?: (message: string, remedy: string) => void,\n): RoomTokenStorage {\n const store = (globalThis as { localStorage?: Storage }).localStorage;\n const key = (roomName: RoomName): string => `mx.meet.pass.${roomName}`;\n if (store === undefined) {\n // NEVER SILENT. A guest in a browser with no storage will be refused the\n // record after they close the tab, and that is worth a line rather than a\n // mystery.\n onDiagnostic?.(\n \"This browser exposes no localStorage, so a guest's meeting pass cannot be kept.\",\n \"A guest who closes the tab will have to open the meeting link again before the \" +\n \"record opens. Signed-in members are unaffected.\",\n );\n return { read: () => null, write: () => undefined, remove: () => undefined };\n }\n return {\n read(roomName) {\n try {\n return store.getItem(key(roomName));\n } catch {\n return null;\n }\n },\n write(roomName, serialized) {\n try {\n store.setItem(key(roomName), serialized);\n } catch {\n /* a full or blocked store is a lost convenience, never a lost join */\n }\n },\n remove(roomName) {\n try {\n store.removeItem(key(roomName));\n } catch {\n /* see write */\n }\n },\n };\n}\n\nexport interface TokenRequest {\n readonly roomName: RoomName;\n readonly identity: MeetIdentity;\n /** Present for a meeting join; absent for an ad-hoc call room. */\n readonly meetingId?: string | undefined;\n /** The public meeting slug, when joining by link without knowing the id. */\n readonly slug?: string | undefined;\n}\n\nexport interface TokenClient {\n /** A currently-valid token, minting or refreshing only when it must. */\n get(request: TokenRequest): Promise<RoomToken>;\n /** Drop the cached token for a room (after a `denied`, or on leave). */\n invalidate(roomName: RoomName): void;\n /** True when the cached token is inside its refresh window. */\n needsRefresh(roomName: RoomName): boolean;\n /**\n * The pass this DEVICE holds for a room, **including an expired one** (MRF-1).\n *\n * 🚨 The expired case is the whole reason this returns the token instead of\n * `null`: \"your pass expired, open the link again\" and \"you were never in\n * this meeting\" are different sentences, and only the caller that can see the\n * expiry can say the right one. Never used to join — `get` mints for that.\n */\n remembered(roomName: RoomName): RoomToken | null;\n}\n\n/** The aidream routes this package calls. ONE place, so a rename is one edit. */\n/**\n * EVERY aidream ROUTE THIS PACKAGE CALLS, in one object.\n *\n * This is the contract in both directions: aidream carries a test\n * (`services/meet/tests/test_meet_service.py`) that reads THIS object out of\n * this source file and fails if the server stops serving one of these paths.\n * The package is the spec.\n *\n * `meetingEnd` is pinned here BEFORE the server serves it (MRI-A6 owns landing\n * it). That is deliberate and it is not a lie on screen: the control that calls\n * it renders, and a 404 from a server that has not landed A6 is reported as the\n * honest sentence \"Ending a meeting is not available on this server yet\" —\n * never a dead button, never a spinner, and never a silent no-op.\n */\nexport const MEET_ROUTES = {\n token: \"/api/v1/meet/token\",\n recordingStart: \"/api/v1/meet/recording/start\",\n recordingStop: \"/api/v1/meet/recording/stop\",\n noteTakerStart: \"/api/v1/meet/agent/start\",\n noteTakerStop: \"/api/v1/meet/agent/stop\",\n /** In-meeting Q&A. Streams NDJSON; body is `{meeting_id, question}` only. */\n intelligenceAsk: \"/api/v1/meet/intelligence/ask\",\n /** A host ends the meeting for everyone. Served by MRI-A6. */\n meetingEnd: \"/api/v1/meet/end\",\n /**\n * THE POST-MEETING RECORD FOR A READER WITH NO DATABASE (MRF-1). A `GET`,\n * authorized by the room token this device already holds, carried in the\n * `x-meet-room-token` header — never a query parameter, because a bearer\n * credential in a URL lands in access logs, referrers and history.\n */\n record: \"/api/v1/meet/record\",\n /** A host chooses what guests may read of ONE meeting (MRF-1). */\n recordAccess: \"/api/v1/meet/record/access\",\n /**\n * Meet wave 1 (0.8): bring every invitee up to date after a write — sends the\n * invitation / update / cancellation emails with their `.ics` and re-queues\n * reminders. Idempotent. `{meeting_id}` is substituted by `meetingPath`.\n */\n meetingAnnounce: \"/api/v1/meet/meetings/{meeting_id}/announce\",\n /** Put a one-off meeting on the caller's own Google Calendar (gated by the server). */\n meetingGoogleCalendar: \"/api/v1/meet/meetings/{meeting_id}/google-calendar\",\n /**\n * Meet wave 3: the recap email after the meeting. `GET` = the draft (subject,\n * body from the wrap-up, who it can go to); `POST` = send what the host\n * reviewed (`dry_run` renders and queues nothing). Never sent automatically.\n */\n meetingFollowUp: \"/api/v1/meet/meetings/{meeting_id}/follow-up\",\n /**\n * Meet wave 2: EVERY in-meeting host power (mute, stop video, mute all, ask to\n * unmute, spotlight, lower hands, co-host, hand over, rename, remove, report).\n * Decided by the server from the meeting itself; a guest's pass rides\n * `x-meet-room-token`.\n */\n moderate: \"/api/v1/meet/moderate\",\n /** Meet wave 2: the SAVED chat — `POST` sends to everyone, `GET ?meeting_id=` reads history. */\n chat: \"/api/v1/meet/chat\",\n} as const;\n\n/** A `MEET_ROUTES` template with its `{meeting_id}` filled in, URL-encoded. */\nexport function meetingPath(template: string, meetingId: string): string {\n return template.replace(\"{meeting_id}\", encodeURIComponent(meetingId));\n}\n\n/** The header the guest's pass rides on. Pinned on both sides. */\nexport const ROOM_TOKEN_HEADER = \"x-meet-room-token\";\n\n/** Refresh at 80% of the token's life — never at the moment it dies. */\nconst REFRESH_RATIO = 0.8;\n\ninterface CacheEntry {\n token: RoomToken;\n mintedAt: number;\n inFlight: Promise<RoomToken> | null;\n}\n\nfunction readString(source: Record<string, unknown>, key: string): string | null {\n const value = source[key];\n return typeof value === \"string\" && value.length > 0 ? value : null;\n}\n\nfunction readBoolean(source: Record<string, unknown>, key: string, fallback: boolean): boolean {\n const value = source[key];\n return typeof value === \"boolean\" ? value : fallback;\n}\n\nconst TOKEN_ROLES: readonly ParticipantRole[] = [\"host\", \"cohost\", \"participant\", \"guest\"];\n\n/** A word this package does not know grants nothing — it is not a host. */\nfunction readRole(source: Record<string, unknown>, key: string): ParticipantRole | null {\n const value = source[key];\n return TOKEN_ROLES.includes(value as ParticipantRole) ? (value as ParticipantRole) : null;\n}\n\nexport function parseRoomToken(body: unknown, roomName: RoomName): RoomToken {\n if (typeof body !== \"object\" || body === null) {\n throw invalidResponse(\"meet.token\", \"the response body was not an object\");\n }\n const envelope = body as Record<string, unknown>;\n // aidream's ordinary envelope is `{ success, data, msg }`; a bare object is\n // accepted too so a self-hosted route does not have to imitate it.\n const payload =\n typeof envelope[\"data\"] === \"object\" && envelope[\"data\"] !== null\n ? (envelope[\"data\"] as Record<string, unknown>)\n : envelope;\n\n const isHost = readBoolean(payload, \"is_host\", false);\n const token = readString(payload, \"token\");\n const serverUrl = readString(payload, \"server_url\") ?? readString(payload, \"serverUrl\");\n const identity = readString(payload, \"identity\");\n const expiresAt = readString(payload, \"expires_at\") ?? readString(payload, \"expiresAt\");\n\n if (token === null || serverUrl === null || identity === null) {\n throw invalidResponse(\n \"meet.token\",\n \"the response is missing token, server_url, or identity — joining with a partial \" +\n \"token would fail inside LiveKit with an opaque error instead of here\",\n );\n }\n if (expiresAt === null) {\n throw invalidResponse(\n \"meet.token\",\n \"the response carries no expires_at. Without it the package cannot refresh before \" +\n \"the token dies, and a long meeting silently loses its ability to reconnect\",\n );\n }\n return {\n token,\n serverUrl,\n roomName,\n identity: identity as ParticipantIdentity,\n displayName: readString(payload, \"display_name\") ?? readString(payload, \"displayName\") ?? identity,\n expiresAt,\n canPublish: readBoolean(payload, \"can_publish\", true),\n canSubscribe: readBoolean(payload, \"can_subscribe\", true),\n canRecord: readBoolean(payload, \"can_record\", false),\n isHost,\n // An older server sends `is_host` and no `role`; a guest join sends neither.\n // Deriving the role from what DID arrive keeps a host a host against a\n // server that has not landed MRI-A11 — and never invents a host from\n // silence, because both fallbacks below grant nothing.\n role:\n readRole(payload, \"role\") ??\n (isHost ? \"host\" : identity.startsWith(\"guest:\") ? \"guest\" : \"participant\"),\n lobby: readBoolean(payload, \"lobby\", false),\n };\n}\n\nexport function createTokenClient(options: TokenClientOptions): TokenClient {\n const cache = new Map<RoomName, CacheEntry>();\n const now = options.now ?? (() => Date.now());\n const storage = options.storage;\n\n /** A GUEST's pass is kept; a member's is not — they can always mint again. */\n function remember(token: RoomToken): void {\n if (storage === undefined) return;\n if (!token.identity.startsWith(\"guest:\")) return;\n storage.write(token.roomName, JSON.stringify(token));\n }\n\n function recall(roomName: RoomName): RoomToken | null {\n if (storage === undefined) return null;\n const raw = storage.read(roomName);\n if (raw === null) return null;\n try {\n const parsed = JSON.parse(raw) as RoomToken;\n // A stored blob that is not a pass for THIS room proves nothing, and a\n // half-written one must not be handed out as a credential.\n if (typeof parsed.token !== \"string\" || parsed.token.length === 0) return null;\n if (parsed.roomName !== roomName) return null;\n return parsed;\n } catch {\n storage.remove(roomName);\n return null;\n }\n }\n\n function expired(entry: CacheEntry): boolean {\n const expiry = Date.parse(entry.token.expiresAt);\n if (Number.isNaN(expiry)) return true;\n const life = expiry - entry.mintedAt;\n if (life <= 0) return true;\n return now() >= entry.mintedAt + life * REFRESH_RATIO;\n }\n\n async function request(input: TokenRequest, retryOnMissingSession: boolean): Promise<RoomToken> {\n const guest = input.identity.userId === null;\n let response: Response;\n try {\n // THE ORGANIZATION IS A HEADER, NOT ONLY A BODY FIELD — and it is put\n // there by `core/api.ts`, the one client, so no caller can forget it\n // (MRI-A16). A body-only `organization_id` looked right and never\n // arrived: the org-admission middleware refuses first, 400, before the\n // meet router is ever reached.\n response = await options.api.request({\n path: MEET_ROUTES.token,\n method: \"POST\",\n // A GUEST HAS NO SESSION AND IS STILL A FIRST-CLASS JOINER (D6), so\n // only an authenticated join requires one.\n requireAuth: !guest,\n operation: \"meet.token\",\n body: {\n room_name: input.roomName,\n ...(input.meetingId !== undefined ? { meeting_id: input.meetingId } : {}),\n ...(input.slug !== undefined ? { slug: input.slug } : {}),\n organization_id: input.identity.organizationId,\n display_name: input.identity.displayName,\n device_id: input.identity.deviceId,\n guest,\n },\n });\n } catch (error) {\n if (\n retryOnMissingSession &&\n (error as { code?: string }).code === \"session-unavailable\"\n ) {\n // ONE retry, after the host's session source has had a turn. This is\n // the cure for \"909 captured errors in 0.6 seconds\": a read that lands\n // between sign-in and token arrival is a lifecycle moment.\n await Promise.resolve();\n return request(input, false);\n }\n throw error;\n }\n\n if (response.status === 401 || response.status === 403) {\n // THE SERVER'S SENTENCE IS THE ONE A PERSON READS. aidream answers every\n // refusal with `{ message, remedy }` (\"The host did not admit you…\", \"A host\n // removed you…\"); the fallback only covers a body that says nothing.\n const said = await serverSentence(response);\n throw new MeetError(\n \"forbidden\",\n said?.message ?? \"You can't join this meeting.\",\n said?.remedy ??\n \"Ask the person who shared the link to let you in, then open the link again.\",\n );\n }\n if (response.status === 404) {\n throw new MeetError(\n \"not-found\",\n \"meet.token: no such meeting\",\n \"The link is wrong or the meeting was deleted. Show the 'meeting not found' screen; \" +\n \"a durable link that 404s is never a retry.\",\n );\n }\n if (response.status === 410) {\n // Meet wave 1: a CANCELLED meeting. The link resolves; the room never opens.\n // The server's own sentence (with the host's reason) is the message.\n const reason = (await serverSentence(response))?.message ?? \"This meeting was cancelled.\";\n throw new MeetError(\n \"cancelled\",\n reason,\n \"Nobody can join a cancelled meeting. Show the cancelled screen with this sentence; \" +\n \"ask the host to schedule a new one.\",\n );\n }\n if (response.status === 423) {\n const said = await serverSentence(response);\n throw new MeetError(\n \"room-locked\",\n said?.message ?? \"The meeting is locked.\",\n said?.remedy ??\n \"The host locked the room. Ask them to unlock it, then join again.\",\n );\n }\n if (response.status === 503) {\n throw new MeetError(\n \"misconfigured\",\n \"meet.token: the meeting service is not configured\",\n \"aidream is missing LIVEKIT_URL / LIVEKIT_API_KEY / LIVEKIT_API_SECRET. That is a \" +\n \"server deployment fix; the client cannot and must not supply them.\",\n );\n }\n if (!response.ok) {\n throw new MeetError(\n \"token\",\n `meet.token: the server returned ${response.status}`,\n \"Transient. The package retries the join once; if it persists check aidream's meet \" +\n \"router logs for the room name in question.\",\n );\n }\n\n return parseRoomToken(await response.json(), input.roomName);\n }\n\n return {\n get(input) {\n const entry = cache.get(input.roomName);\n if (entry !== undefined) {\n if (entry.inFlight !== null) return entry.inFlight;\n if (!expired(entry)) return Promise.resolve(entry.token);\n }\n // SINGLE FLIGHT. Every concurrent caller shares this promise, so a strict\n // mode double-mount cannot mint two tokens for one identity.\n const pending = request(input, true)\n .then((token) => {\n cache.set(input.roomName, { token, mintedAt: now(), inFlight: null });\n // MRF-1: kept HERE, at the one place a pass is ever minted, so no\n // future caller can acquire one without it being remembered.\n remember(token);\n return token;\n })\n .catch((error: unknown) => {\n // A failure is NEVER cached — one wobble would otherwise leave the\n // room unjoinable until a reload.\n cache.delete(input.roomName);\n throw error;\n });\n cache.set(input.roomName, {\n token: entry?.token ?? placeholder(input.roomName),\n mintedAt: entry?.mintedAt ?? now(),\n inFlight: pending,\n });\n return pending;\n },\n invalidate(roomName) {\n cache.delete(roomName);\n // 🚨 THE STORED PASS SURVIVES `invalidate` ON PURPOSE. This is called on\n // leave and after a refused mint, and a guest leaving a meeting is\n // exactly the person who comes back to read its summary. What `get`\n // refuses to REUSE and what the record read may PRESENT are two different\n // questions; clearing the pass here would answer the second one wrong.\n },\n needsRefresh(roomName) {\n const entry = cache.get(roomName);\n return entry === undefined || expired(entry);\n },\n remembered(roomName) {\n // The in-flight `placeholder()` occupies the cache slot with an EMPTY\n // token string and is never handed out — including here, where handing it\n // out would present \"\" as a credential and earn a 403 that means nothing.\n const live = cache.get(roomName)?.token;\n if (live !== undefined && live.token.length > 0) return live;\n return recall(roomName);\n },\n };\n}\n\n/** Never handed out: it only occupies the slot while a mint is in flight. */\nfunction placeholder(roomName: RoomName): RoomToken {\n return {\n token: \"\",\n serverUrl: \"\",\n roomName,\n identity: \"\" as ParticipantIdentity,\n displayName: \"\",\n expiresAt: new Date(0).toISOString(),\n canPublish: false,\n canSubscribe: false,\n canRecord: false,\n isHost: false,\n role: \"participant\",\n lobby: false,\n };\n}\n\n/**\n * The `{ message, remedy }` aidream puts on a refusal (`MeetError` →\n * `{ error, message, user_message, remedy }`, or FastAPI's `{ detail: {…} }`),\n * or null when the body carries no sentence.\n */\nasync function serverSentence(\n response: Response,\n): Promise<{ message: string; remedy: string | undefined } | null> {\n try {\n const body = (await response.json()) as Record<string, unknown> | null;\n const source =\n body !== null && typeof body.detail === \"object\" && body.detail !== null\n ? (body.detail as Record<string, unknown>)\n : body;\n if (source === null) return null;\n const message =\n typeof source.user_message === \"string\" && source.user_message.trim() !== \"\"\n ? source.user_message\n : typeof source.message === \"string\" && source.message.trim() !== \"\"\n ? source.message\n : null;\n if (message === null) return null;\n const remedy =\n typeof source.remedy === \"string\" && source.remedy.trim() !== \"\" ? source.remedy : undefined;\n return { message, remedy };\n } catch {\n return null;\n }\n}\n","/**\n * THE ONE WAY THIS PACKAGE TALKS TO AIDREAM (MRI-A16).\n *\n * 🚨 **Every request to the aidream server carries `x-organization-id`, and the\n * only way to guarantee \"every\" is for there to be ONE place that builds the\n * request.** aidream's org-admission middleware refuses an authenticated\n * request that does not name the organization it is acting in — 400\n * `organization_required`, before the router is ever reached.\n *\n * 0.1.3 learned that lesson and put the header on the three meet callers by\n * hand. That fixed the instances and left the CLASS wide open, and on\n * 2026-09-09 the class collected its next victim: `<RecordingPlayer>` fetched\n * `GET /files/{id}/download?inline=1` through a bare `fetch` with only a bearer\n * token, so a perfectly landed 1.38 MB recording could not be played by the\n * host who made it (MRI-C8; the identical URL returned `200 video/mp4` the\n * moment the header was added by hand). A fourth caller was written months\n * after the lesson and never heard it, because a lesson written into three call\n * sites is not a lesson, it is three copies of a workaround.\n *\n * So: this module owns the base URL, the organization header and the bearer\n * token, and `api.test.ts` holds a guard that FAILS THE BUILD if any other file\n * in the package calls `fetch(` against a base URL or points an element `src=`\n * at one. A new caller cannot be written without the header any more.\n *\n * 🚨 **HOW A `<video>` GETS ITS BYTES, given that signed URLs are eradicated.**\n * A browser media element cannot attach a header, so a bare\n * `src=\"https://server…/files/{id}/download\"` carries no session and no\n * organization and is refused — which is precisely what MRI-C8 saw. The\n * platform's answer is NOT a signed URL (`aidream/api/routers/files` mints\n * none, by law) but the FILE-SESSION COOKIE: `POST /files/session` mints an\n * HttpOnly `SameSite=None` cookie that the auth middleware accepts on exactly\n * the GET byte-serving routes (`COOKIE_AUTH_PATH_RE` in\n * `matrx_connect/middleware/session_cookie.py`), and a cookie rides a media\n * request that a header cannot. Every private `<img>`/`<video>` in the platform\n * already renders this way.\n *\n * So `fileMedia` mints the cookie and hands back a STREAMING url — which is\n * what lets a person scrub a two-hour recording instead of waiting for a\n * gigabyte to arrive. When the mint is refused (no session, an older server,\n * a browser blocking third-party cookies) it falls back to reading the bytes\n * with the organization header into a `blob:` url — and it SAYS it did, with\n * the reason, because a silent fallback that downloads a gigabyte is exactly\n * the kind of automatic intervention that must announce itself.\n */\n\nimport { MeetError, normalizeMeetError } from \"./errors\";\nimport type { OrganizationId } from \"./types\";\n\n/**\n * How the host tells us who is asking. Returns null before sign-in resolves,\n * and for a guest, who has no session at all and is still a first-class joiner.\n *\n * It lives HERE rather than in `tokens.ts` (where it was born) because this is\n * now the one module that turns a session into a request.\n */\nexport type AccessTokenSource = () => Promise<string | null>;\n\n/** The header aidream's org-admission middleware demands. One definition. */\nexport const ORGANIZATION_HEADER = \"x-organization-id\";\n\nexport interface MeetApiOptions {\n /** aidream's origin. Never a LiveKit or provider URL. */\n baseUrl: string;\n /** Named on EVERY request; the server refuses one that omits it. */\n organizationId: OrganizationId;\n accessToken: AccessTokenSource;\n fetchImpl?: typeof fetch | undefined;\n}\n\nexport interface MeetApiRequest {\n /** An absolute path on the aidream origin, e.g. `/api/v1/meet/token`. */\n path: string;\n method?: \"GET\" | \"POST\" | undefined;\n /** JSON body. Serialized here so no caller can forget the content type. */\n body?: Record<string, unknown> | undefined;\n /**\n * `true` — refuse before the wire when there is no session, with the given\n * operation named. `false` — send whatever session exists, or none (a guest\n * minting a room token is a real, authorized case).\n */\n requireAuth?: boolean | undefined;\n /** Names the caller in every error this raises. */\n operation: string;\n /** Extra headers. May not override the organization header. */\n headers?: Record<string, string> | undefined;\n /**\n * `\"include\"` for the ONE request that mints the file-session cookie — a\n * `Set-Cookie` on a cross-origin response is dropped without it.\n */\n credentials?: RequestCredentials | undefined;\n /** Cancels the request. The Q&A stream is abortable by the person asking. */\n signal?: AbortSignal | undefined;\n}\n\nexport interface MeetApi {\n readonly baseUrl: string;\n readonly organizationId: OrganizationId;\n /** The URL a request to `path` would go to. For diagnostics, never for fetching. */\n url(path: string): string;\n /** One request, with the organization header and the session already on it. */\n request(input: MeetApiRequest): Promise<Response>;\n /**\n * Read an authenticated file into a `blob:` URL an element can load. The\n * caller MUST `URL.revokeObjectURL` it — a leaked one pins the whole file in\n * memory for the life of the tab.\n */\n fetchObjectUrl(input: MeetApiRequest): Promise<string>;\n /**\n * A url a `<video>`/`<img>` can load for a platform file. Streams when the\n * file-session cookie can be minted; otherwise reads the bytes with the\n * organization header and says why it had to.\n */\n fileMedia(fileId: string, operation: string): Promise<MeetFileMedia>;\n /** Re-mint the file-session cookie. Returns whether it now exists. */\n refreshFileSession(): Promise<boolean>;\n}\n\n/** Where a media element's bytes are coming from, and whether that is plan A. */\nexport interface MeetFileMedia {\n readonly url: string;\n /** `stream` seeks and starts instantly; `bytes` is a fully downloaded blob. */\n readonly kind: \"stream\" | \"bytes\";\n /**\n * Set only for `bytes`, and never null-and-hoping: the sentence a surface\n * shows to explain why it had to download the whole file first.\n */\n readonly fallbackReason: string | null;\n}\n\n/** `POST /files/session` — mints the `mx_files_session` cookie (files law). */\nexport const FILE_SESSION_PATH = \"/files/session\";\n\nexport function createMeetApi(options: MeetApiOptions): MeetApi {\n const doFetch = options.fetchImpl ?? globalThis.fetch;\n const base = options.baseUrl.replace(/\\/+$/, \"\");\n\n async function headersFor(input: MeetApiRequest): Promise<Record<string, string>> {\n const token = await options.accessToken();\n if (token === null && input.requireAuth === true) {\n throw new MeetError(\n \"session-unavailable\",\n `${input.operation}: this request requires a signed-in session`,\n \"Render the signed-out or guest surface rather than a control that will be refused.\",\n );\n }\n return {\n ...(input.headers ?? {}),\n ...(input.body !== undefined ? { \"content-type\": \"application/json\" } : {}),\n // 🚨 LAST, so nothing a caller passes can shadow it.\n [ORGANIZATION_HEADER]: options.organizationId,\n ...(token !== null ? { authorization: `Bearer ${token}` } : {}),\n };\n }\n\n return {\n baseUrl: base,\n organizationId: options.organizationId,\n\n url(path) {\n return `${base}${path}`;\n },\n\n async request(input) {\n const headers = await headersFor(input);\n try {\n return await doFetch(`${base}${input.path}`, {\n method: input.method ?? (input.body !== undefined ? \"POST\" : \"GET\"),\n headers,\n ...(input.credentials !== undefined ? { credentials: input.credentials } : {}),\n ...(input.signal !== undefined ? { signal: input.signal } : {}),\n ...(input.body !== undefined ? { body: JSON.stringify(input.body) } : {}),\n });\n } catch (error) {\n throw normalizeMeetError(error, input.operation);\n }\n },\n\n async fetchObjectUrl(input) {\n const response = await this.request(input);\n if (response.status === 401 || response.status === 403) {\n throw new MeetError(\n \"forbidden\",\n `${input.operation}: you are not allowed to read this file`,\n \"The file is safe — this is a read decision, not a lost file. Sign in with an \" +\n \"account in this meeting's organization and try again.\",\n );\n }\n if (!response.ok) {\n throw new MeetError(\n \"transport\",\n `${input.operation}: the server returned ${response.status}`,\n \"The file itself is unaffected. Try again; if it repeats, the platform files \" +\n \"route is the thing to look at, not the recording.\",\n );\n }\n return URL.createObjectURL(await response.blob());\n },\n\n async refreshFileSession() {\n try {\n const response = await this.request({\n path: FILE_SESSION_PATH,\n method: \"POST\",\n // `Set-Cookie` on a cross-origin response is DROPPED without this.\n credentials: \"include\",\n requireAuth: true,\n operation: \"meet.files.session\",\n });\n return response.ok;\n } catch {\n // A refused mint is a fallback, never a failure: the caller reads the\n // bytes with the header instead and says so.\n return false;\n }\n },\n\n async fileMedia(fileId, operation) {\n const path = fileDownloadPath(fileId);\n if (await this.refreshFileSession()) {\n return { url: `${base}${path}`, kind: \"stream\", fallbackReason: null };\n }\n return {\n url: await this.fetchObjectUrl({ path, operation }),\n kind: \"bytes\",\n fallbackReason:\n \"This file was downloaded in full before playing, because the browser session that \" +\n \"lets it stream could not be established. Downloading can take longer, and seeking \" +\n \"is unavailable until it finishes.\",\n };\n },\n };\n}\n\n/** `GET /files/{id}/download?inline=1` — the platform files route (R3). */\nexport function fileDownloadPath(fileId: string): string {\n return `/files/${encodeURIComponent(fileId)}/download?inline=1`;\n}\n","/**\n * THE MEET CHANNEL NAMESPACES.\n *\n * Zero hand-rolled `.channel(` in this package (the realtime doctrine). Every\n * topic is declared through `@ai-matrx/realtime`'s registry, which refuses a\n * colliding re-declaration.\n *\n * THREE channels, each because it has a different AUDIENCE:\n *\n * - `meet-user` (per user): where a call REACHES you — the ring, the cancel,\n * the \"answered on another device\". You are subscribed to this everywhere the\n * provider is mounted, whether or not you are in a meeting.\n * - `meet-room` (per room): the pre-media room — who is knocking, who was\n * admitted, whether recording started. It carries the moments that happen\n * BEFORE and AFTER media, which LiveKit's own data plane cannot: a guest in\n * the lobby is not in the LiveKit room yet, by construction (D6).\n * - `meet-meeting` (per meeting): the durable record's feed — transcript\n * segments, notes, the recording row going `available` — so a surface that is\n * NOT in the call (a meeting page, an admin console) stays live.\n *\n * 🚨 The in-MEDIA control plane (hand raise, reactions, in-room chat) rides\n * LiveKit data messages, NOT these channels — see `DATA_TOPICS`. Splitting them\n * this way is deliberate: anything that must reach a guest with no Supabase\n * session travels on the media plane, where their room token is the authority.\n */\n\nimport { defineChannelNamespace, type ChannelNamespace } from \"@ai-matrx/realtime\";\nimport { globalSlot } from \"./slot\";\nimport type { MeetingId, RoomName, UserId } from \"./types\";\n\ninterface Namespaces {\n user: ChannelNamespace;\n room: ChannelNamespace;\n meeting: ChannelNamespace;\n}\n\nfunction namespaces(): Namespaces {\n // `defineChannelNamespace` throws on a conflicting re-declaration, so these\n // are created lazily through a `globalThis` slot: with dual ESM/CJS output\n // the module can be evaluated twice in one process, and a second identical\n // declaration must be a no-op rather than a crash.\n return globalSlot<Namespaces>(\"channel-namespaces\", () => ({\n user: defineChannelNamespace({\n namespace: \"meet-user\",\n parts: [\"userId\"],\n description:\n \"One user's calling presence: incoming rings, cancellations, and the \" +\n \"answered-elsewhere signal that stops every other device ringing.\",\n }),\n room: defineChannelNamespace({\n namespace: \"meet-room\",\n parts: [\"roomName\"],\n description:\n \"One media room's out-of-band plane: lobby knocks and admissions, lock \" +\n \"state, and recording state — the moments that happen before a guest is \" +\n \"in the LiveKit room at all.\",\n }),\n meeting: defineChannelNamespace({\n namespace: \"meet-meeting\",\n parts: [\"meetingId\"],\n description:\n \"One meeting record's live feed: transcript segments, AI notes, and the \" +\n \"recording row settling — for surfaces that are not in the call.\",\n }),\n }));\n}\n\nexport function userTopic(userId: UserId): string {\n return namespaces().user.topic({ userId });\n}\n\nexport function roomTopic(roomName: RoomName): string {\n return namespaces().room.topic({ roomName });\n}\n\nexport function meetingTopic(meetingId: MeetingId): string {\n return namespaces().meeting.topic({ meetingId });\n}\n\n/** Broadcast event names. One place, so a sender and a receiver cannot drift. */\nexport const MEET_EVENTS = {\n /** A call is ringing you. Carries the whole invite; no follow-up read. */\n ring: \"mx.call.ring\",\n /** The caller hung up before you answered. */\n cancel: \"mx.call.cancel\",\n /** You answered (or declined) on another device. Stop ringing here. */\n settled: \"mx.call.settled\",\n /** Someone is in the lobby. Hosts render the knock. */\n knock: \"mx.lobby.knock\",\n /** A host decided. The knocker learns it here — they have no DB read. */\n admission: \"mx.lobby.admission\",\n /** The room was locked or unlocked. */\n lock: \"mx.room.lock\",\n /** Recording started or stopped. EVERY participant renders the indicator. */\n recording: \"mx.room.recording\",\n} as const;\n\n/**\n * 🚨 `mx.meeting.transcript` and `mx.meeting.note` WERE declared here and\n * emitted and subscribed by nothing — a broadcast fallback that existed only as\n * a name (MRI-A10 found it; feedback `b25db4d4`). They are gone. The thing they\n * described is real now and lives somewhere better: the platform publishes the\n * durable rows into the LIVEKIT ROOM under `matrx.meet.*` (`core/room-events.ts`,\n * MRI-A12), where a session-less guest's room token is the authority. Sending\n * them over a Supabase broadcast channel would have required the guest to hold a\n * Supabase connection, which is the exact thing they do not have.\n */\n\nexport type MeetEvent = (typeof MEET_EVENTS)[keyof typeof MEET_EVENTS];\n","/**\n * PROCESS-GLOBAL STATE LIVES HERE, NEVER IN A MODULE `let`.\n *\n * With `splitting: false` dual ESM/CJS output, one module can be instantiated\n * TWICE in a single process (a Next.js app that imports ESM while its Jest\n * suite requires CJS is the ordinary case). A module-level `let` therefore\n * silently splits into two independent values — which is how the channel\n * namespace registry \"randomly\" re-declares, and how a device-permission cache\n * \"randomly\" forgets what the user already granted.\n *\n * Everything process-global goes through `globalThis` + `Symbol.for`, and the\n * packed-tarball canary proves the slots are shared across module graphs.\n */\nconst NAMESPACE = \"ai-matrx.meet\";\n\nexport function globalSlot<T>(name: string, create: () => T): T {\n const key = Symbol.for(`${NAMESPACE}.${name}`);\n const host = globalThis as Record<symbol, unknown>;\n const existing = host[key];\n if (existing !== undefined) return existing as T;\n const created = create();\n host[key] = created;\n return created;\n}\n\n/** Test-only: drop a slot so a suite can start from a clean registry. */\nexport function resetGlobalSlotForTests(name: string): void {\n const key = Symbol.for(`${NAMESPACE}.${name}`);\n delete (globalThis as Record<symbol, unknown>)[key];\n}\n","/**\n * THE MEET DOMAIN MODEL.\n *\n * D3: an audio call, a video call, and a meeting are ONE thing — a room. An\n * audio call is a room with video off; a meeting is a room plus scheduling,\n * lobby and host metadata. That ruling is expressed here as ONE `MeetRoom`\n * identity carried by both `/calls` and `/meetings`, not as three parallel\n * hierarchies that drift.\n *\n * Identity-bearing values are BRANDED (C22). A `MeetingId` and a `RoomName` are\n * both strings and are NOT interchangeable — passing the meeting's row id where\n * LiveKit wants the room name produces a room nobody else joins, which looks\n * exactly like \"the other person's camera is broken\".\n */\n\ndeclare const brand: unique symbol;\ntype Brand<T, B extends string> = T & { readonly [brand]: B };\n\nexport type MeetingId = Brand<string, \"MeetingId\">;\nexport type CallId = Brand<string, \"CallId\">;\n/** The LiveKit room name. THE MEDIA ROOM KEY — durable for a meeting link. */\nexport type RoomName = Brand<string, \"RoomName\">;\nexport type UserId = Brand<string, \"UserId\">;\nexport type OrganizationId = Brand<string, \"OrganizationId\">;\n/** LiveKit participant identity. `user:<uuid>` or `guest:<opaque>`. */\nexport type ParticipantIdentity = Brand<string, \"ParticipantIdentity\">;\n\nexport const asMeetingId = (value: string): MeetingId => value as MeetingId;\nexport const asCallId = (value: string): CallId => value as CallId;\nexport const asRoomName = (value: string): RoomName => value as RoomName;\nexport const asUserId = (value: string): UserId => value as UserId;\nexport const asOrganizationId = (value: string): OrganizationId =>\n value as OrganizationId;\nexport const asParticipantIdentity = (value: string): ParticipantIdentity =>\n value as ParticipantIdentity;\n\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\nexport type JsonObject = { [key: string]: JsonValue };\n\n/** Audio-only or with video. A call escalates; it never becomes a new call. */\nexport type CallMode = \"audio\" | \"video\";\n\n/**\n * WHO IS IN THE ROOM, as far as authorization is concerned.\n *\n * A guest has no `userId` — by construction, not by convention. Everything that\n * requires authentication (host powers, recording, starting a call) takes a\n * `userId` and therefore cannot compile against a guest identity (D6).\n */\nexport interface MeetIdentity {\n readonly userId: UserId | null;\n readonly organizationId: OrganizationId;\n readonly displayName: string;\n readonly avatarUrl: string | null;\n /** Stable per-device value so a reconnect keeps ONE LiveKit identity. */\n readonly deviceId: string;\n}\n\nexport function isGuest(identity: MeetIdentity): boolean {\n return identity.userId === null;\n}\n\n/**\n * WHO SOMEBODY IS IN A ROOM — the SERVER's word, never this client's (MRI-A11).\n *\n * `host` is `meet_meetings.host_user_id` or a real `iam` grant on the meeting;\n * `participant` is an authenticated member of the meeting's organization;\n * `guest` is a link-follower with no session. Organization membership is\n * TENANCY and never permission, which is why \"member of the org\" lands on\n * `participant` and not on `host`.\n *\n * `cohost` has no server-side minter yet and is kept because the rank ladder\n * below is the thing that stops a co-host from removing the host; the moment a\n * co-host grant exists it slots in without a second vocabulary.\n */\nexport type ParticipantRole = \"host\" | \"cohost\" | \"participant\" | \"guest\";\n\n/** Rank, so \"can this actor do that to that participant\" is one comparison. */\nexport const ROLE_RANK: Readonly<Record<ParticipantRole, number>> = {\n host: 3,\n cohost: 2,\n participant: 1,\n guest: 0,\n};\n\n/**\n * 🚨 THE ONE PREDICATE FOR \"DOES THIS PERSON HOLD HOST POWERS\".\n *\n * Every host control in this package answers this question and no other. It is\n * a pure function of a SERVER-minted role, so there is no path by which a\n * client's own state can grant it anything.\n */\nexport function isHostRole(role: ParticipantRole): boolean {\n return role === \"host\" || role === \"cohost\";\n}\n\n/**\n * THE LOBBY LADDER (D6). A guest link-follower starts `knocking`; the host\n * admits or denies. An authenticated member of the meeting's org is `admitted`\n * on arrival unless the meeting is locked.\n */\nexport type AdmissionState = \"knocking\" | \"admitted\" | \"denied\" | \"removed\";\n\nexport interface LobbyEntry {\n readonly identity: ParticipantIdentity;\n readonly displayName: string;\n readonly avatarUrl: string | null;\n readonly userId: UserId | null;\n readonly state: AdmissionState;\n readonly knockedAt: string;\n readonly decidedAt: string | null;\n readonly decidedBy: UserId | null;\n}\n\nexport type ConnectionQuality = \"excellent\" | \"good\" | \"poor\" | \"lost\" | \"unknown\";\n\n/** One person in the room, as the UI needs them. Media state is a FACT here. */\nexport interface MeetParticipant {\n readonly identity: ParticipantIdentity;\n readonly userId: UserId | null;\n readonly displayName: string;\n readonly avatarUrl: string | null;\n readonly role: ParticipantRole;\n /**\n * Whether the SERVER granted this participant the power to start a recording\n * (MRI-A11). It is not `role === \"host\"`: a meeting whose recording policy is\n * `always-on` is the server's to start and a host may not touch it, and a\n * `disabled` policy grants it to nobody. The client renders this; it never\n * recomputes the policy.\n */\n readonly canRecord: boolean;\n readonly isLocal: boolean;\n readonly isAgent: boolean;\n readonly micEnabled: boolean;\n readonly cameraEnabled: boolean;\n readonly screenSharing: boolean;\n readonly speaking: boolean;\n readonly handRaised: boolean;\n /**\n * When the hand went up (epoch ms), or null. The HAND QUEUE is ordered by it —\n * first raised, first called on (Meet wave 2). Optional so a roster built by a\n * host before 0.8 still type-checks.\n */\n readonly handRaisedAt?: number | null | undefined;\n readonly quality: ConnectionQuality;\n readonly joinedAt: string;\n /**\n * LiveKit participant attributes, verbatim. The note-taker announces itself\n * here (`matrx.agent.consent_notice`), which is how a consent notice can be\n * rendered for a participant whose token metadata this client cannot read.\n */\n readonly attributes: Readonly<Record<string, string>>;\n}\n\nexport type RoomPhase =\n | \"idle\"\n | \"requesting-token\"\n | \"lobby\"\n | \"connecting\"\n | \"connected\"\n | \"reconnecting\"\n | \"left\"\n | \"failed\";\n\nexport type MeetingKind = \"instant\" | \"scheduled\" | \"recurring\";\n\nexport interface MeetingRecord {\n readonly id: MeetingId;\n readonly organizationId: OrganizationId;\n /** Durable: the same room name before, during, and after (R3). */\n readonly roomName: RoomName;\n /** The public slug in a meeting link. Durable for recurring meetings. */\n readonly slug: string;\n readonly title: string;\n readonly kind: MeetingKind;\n readonly hostUserId: UserId;\n readonly scheduledFor: string | null;\n readonly scheduledDurationMinutes: number | null;\n readonly startedAt: string | null;\n readonly endedAt: string | null;\n readonly locked: boolean;\n readonly lobbyEnabled: boolean;\n readonly recordingPolicy: RecordingPolicy;\n readonly aiEnabled: boolean;\n readonly metadata: JsonObject;\n /*\n * ── MEET WAVE 1 — management (0.8). Always present on a row read from the\n * database by this package; optional in the type only so a hand-built\n * fixture from before 0.8 still compiles.\n */\n /** IANA zone the meeting's wall-clock time is authored in (`America/Los_Angeles`). */\n readonly timeZone?: string;\n /** Description / agenda text. */\n readonly agenda?: string | null;\n /** RFC 5545 RRULE subset — one row and one durable link per series. */\n readonly recurrenceRule?: string | null;\n /** Signed-in members and invitees may enter before a host arrives. */\n readonly joinBeforeHost?: boolean;\n /** Cancel is a STATE: the link still resolves and says so; nobody can join. */\n readonly cancelledAt?: string | null;\n readonly cancellationReason?: string | null;\n /** Archived (soft deleted). Restorable by the host or a co-host. */\n readonly deletedAt?: string | null;\n /** iCalendar SEQUENCE — bumped by the database on every reschedule and on cancel. */\n readonly calendarSequence?: number;\n /** Row version, for the compare-and-swap in `updateMeeting`. */\n readonly version?: number;\n}\n\n/* ─────────────────────────────── MEET WAVE 1 — management vocabulary (0.8) */\n\n/** An invitee's answer. `needs_action` = not answered yet (iCalendar NEEDS-ACTION). */\nexport type RsvpState = \"needs_action\" | \"accepted\" | \"declined\" | \"tentative\";\n/** The answers a person can give. */\nexport type RsvpAnswer = Exclude<RsvpState, \"needs_action\">;\n/** A co-host holds host moderation through a real `iam` admin grant on the meeting. */\nexport type InviteeRole = \"invitee\" | \"cohost\";\n\n/** One person a meeting was sent to (`communication.meet_invitees`). */\nexport interface MeetingInvitee {\n readonly id: string;\n readonly meetingId: MeetingId;\n /** Set when the person has an account — they skip the waiting room and answer in-app. */\n readonly userId: UserId | null;\n readonly email: string | null;\n readonly displayName: string | null;\n readonly role: InviteeRole;\n readonly rsvpState: RsvpState;\n readonly respondedAt: string | null;\n readonly rsvpNote: string | null;\n /** The calendar_sequence of the last invitation they were sent; null = never told. */\n readonly lastSentSequence: number | null;\n readonly lastSentAt: string | null;\n}\n\n/** Who to invite: an account (`userId`) or an address (`email`), or both. */\nexport interface InviteeInput {\n readonly userId?: UserId | undefined;\n readonly email?: string | undefined;\n readonly displayName?: string | undefined;\n /** Omit to keep an existing invitee's role; `cohost` needs the host or a co-host. */\n readonly role?: InviteeRole | undefined;\n}\n\n/** Where one occurrence of a meeting stands. */\nexport type OccurrenceState = \"scheduled\" | \"moved\" | \"cancelled\";\n\n/** One occurrence — for a one-off meeting, the meeting itself. */\nexport interface MeetingOccurrence {\n readonly meetingId: MeetingId;\n /** The start the rule generates (iCalendar RECURRENCE-ID). The key for exceptions. */\n readonly originalStart: string;\n /** When it actually happens (differs from `originalStart` only when `moved`). */\n readonly occurrenceStart: string;\n readonly durationMinutes: number | null;\n readonly state: OccurrenceState;\n readonly sequence: number;\n}\n\n/** One row of the Upcoming list — an occurrence plus what the list shows about its meeting. */\nexport interface UpcomingOccurrence extends MeetingOccurrence {\n readonly organizationId: OrganizationId;\n readonly title: string;\n readonly slug: string;\n readonly kind: MeetingKind;\n readonly hostUserId: UserId;\n readonly timeZone: string;\n readonly meetingCancelled: boolean;\n /** The signed-in reader's own answer, when they are an invitee. */\n readonly myRsvp: RsvpState | null;\n /** `host`, `cohost` or `invitee` — null when the reader simply can see it (org member). */\n readonly myRole: \"host\" | InviteeRole | null;\n}\n\n/** An exception row (`communication.meet_occurrence_overrides`). */\nexport interface OccurrenceOverride {\n readonly id: string;\n readonly meetingId: MeetingId;\n readonly originalStart: string;\n readonly state: \"cancelled\" | \"moved\";\n readonly newStart: string | null;\n readonly newDurationMinutes: number | null;\n readonly reason: string | null;\n readonly calendarSequence: number;\n /** Set when the exception was withdrawn (`restore`) and the occurrence is back on schedule. */\n readonly deletedAt: string | null;\n}\n\n/** Settings a meeting carries; unset ones come from the person's / organization's knobs. */\nexport interface MeetingSettings {\n readonly lobbyEnabled?: boolean | undefined;\n readonly recordingPolicy?: RecordingPolicy | undefined;\n readonly aiEnabled?: boolean | undefined;\n readonly joinBeforeHost?: boolean | undefined;\n}\n\n/** A partial edit. `null` clears a clearable field (agenda, recurrence rule, time). */\nexport interface MeetingChanges extends MeetingSettings {\n readonly title?: string | undefined;\n readonly agenda?: string | null | undefined;\n readonly timeZone?: string | undefined;\n readonly scheduledFor?: string | null | undefined;\n readonly scheduledDurationMinutes?: number | null | undefined;\n readonly recurrenceRule?: string | null | undefined;\n}\n\n/** What the emailed RSVP link shows and answers (no account needed). */\nexport type RsvpInvitation =\n | {\n readonly ok: true;\n readonly meeting: {\n readonly title: string;\n readonly slug: string;\n readonly scheduledFor: string | null;\n readonly durationMinutes: number | null;\n readonly timeZone: string;\n readonly agenda: string | null;\n readonly recurrenceRule: string | null;\n readonly cancelledAt: string | null;\n readonly cancellationReason: string | null;\n readonly endedAt: string | null;\n };\n readonly invitee: {\n readonly displayName: string | null;\n readonly email: string | null;\n readonly rsvpState: RsvpState;\n readonly respondedAt: string | null;\n };\n }\n | { readonly ok: false; readonly message: string };\n\n/** Org-configurable, never hardcoded taste (Law 6 / \"opinions become knobs\"). */\nexport type RecordingPolicy = \"disabled\" | \"host-controlled\" | \"always-on\";\n\nexport type RecordingState =\n | \"idle\"\n | \"starting\"\n | \"recording\"\n | \"stopping\"\n | \"processing\"\n | \"available\"\n /** Bytes were purged under retention; notes and transcript remain durable. */\n | \"expired\"\n | \"failed\";\n\n/**\n * WHICH transport last said what the recording is doing (MRI-A16).\n *\n * `local` — this browser's own optimistic `starting`/`stopping`, which is all\n * the indicator ever had through 0.4.7, and the reason it never went solid.\n * `room` — a `matrx.meet.recording` packet, the ONLY feed a guest has.\n * `record` — the durable `meet_recordings` row. It outranks both (D16).\n */\nexport type RecordingSource = \"local\" | \"room\" | \"record\";\n\n/** The server's durable retention receipt; never inferred from a browser clock. */\nexport interface RecordingRetention {\n readonly operationId: string;\n readonly policyId: string;\n readonly policyUpdatedAt: string;\n readonly phase: \"warning\" | \"expired\";\n readonly dueAt: string;\n readonly expiredAt: string | null;\n}\n\nexport interface RecordingRecord {\n readonly id: string;\n readonly meetingId: MeetingId;\n readonly state: RecordingState;\n readonly startedAt: string | null;\n readonly endedAt: string | null;\n readonly startedBy: UserId | null;\n /** The PLATFORM file id. Never a provider URL (R3). */\n readonly fileId: string | null;\n readonly failureReason: string | null;\n /** Present when central retention warned or purged this recording. */\n readonly retention: RecordingRetention | null;\n}\n\n/**\n * WHERE A TRANSCRIPT LINE CAME FROM — and therefore how much it is worth.\n *\n * D16: `lk.transcription` is published by a room participant and its\n * `sender_identity` is client-supplied and unvalidated by LiveKit, so a caption\n * is a HINT — good enough to read live, never good enough to reason from. A\n * `record` line is a durable `meet_transcript_segments` row written server-side\n * by the note-taker: that is the transcript. A record always beats a caption;\n * a caption never overwrites a record.\n */\nexport type TranscriptSource = \"caption\" | \"record\";\n\nexport interface TranscriptSegment {\n readonly id: string;\n readonly meetingId: MeetingId;\n readonly identity: ParticipantIdentity;\n readonly speaker: string;\n readonly text: string;\n readonly startedAt: string;\n /** Interim text is replaced in place by its final; it is never appended. */\n readonly final: boolean;\n readonly source: TranscriptSource;\n /**\n * The `lk.segment_id` this line was captioned under, when known. A durable\n * row carries it too (the worker writes it into the row's metadata), which is\n * what lets a record REPLACE the caption it supersedes rather than doubling it.\n */\n readonly captionId: string | null;\n}\n\n/**\n * SOMEBODY WHO WAS IN THE MEETING — the durable `meet_participants` row, which\n * outlives the LiveKit room (MRI-D2). `MeetParticipant` above is a live tile;\n * THIS is the attendance record a person reads a week later.\n */\nexport interface MeetingAttendee {\n readonly id: string;\n readonly meetingId: MeetingId;\n readonly identity: ParticipantIdentity;\n readonly displayName: string;\n readonly avatarUrl: string | null;\n readonly userId: UserId | null;\n readonly role: ParticipantRole;\n readonly admissionState: AdmissionState;\n readonly isAgent: boolean;\n readonly joinedAt: string | null;\n readonly leftAt: string | null;\n}\n\nexport type MeetingNoteKind = \"note\" | \"decision\" | \"action-item\";\n\n/**\n * ONE ROW OF WHAT THE MEETING DECIDED. `meet_notes.kind` is a live CHECK\n * constraint of exactly three values (D5) — there is no `summary` kind and no\n * `transcript` kind — so the wrap-up summary is a `note` carrying\n * `metadata.role = \"summary\"`, and a live-window note carries `metadata.window`.\n * Both are projected here so the UI never re-reads raw metadata.\n */\nexport interface MeetingNote {\n readonly id: string;\n readonly meetingId: MeetingId;\n readonly text: string;\n readonly createdAt: string;\n readonly kind: MeetingNoteKind;\n /** Set ONLY when the assignee resolved to a real user (D18). */\n readonly assigneeUserId: UserId | null;\n /** Who the item is for, as a person reads it. A guest keeps their name here. */\n readonly assigneeDisplayName: string | null;\n /** `\"summary\"` for the wrap-up; `null` for everything else. */\n readonly role: \"summary\" | null;\n /** The live-notes window index this came out of, when it came from one. */\n readonly window: number | null;\n /**\n * 🚨 THE WRAP-UP IS THE AUTHORITATIVE POST-MEETING SET (D20).\n *\n * A live-notes window and the wrap-up both write decisions and action items,\n * and on production 2026-09-09 meeting `9cb-39f8-782` carried the SAME\n * decision twice — once from the note-taker at 04:43:57 and once from the\n * wrap-up at 04:47:15 — and the record view listed both. A reader cannot tell\n * a repeated decision from two decisions.\n *\n * So when the wrap-up lands, the server MARKS the window-written decisions\n * and action items it supersedes (`metadata.superseded_by` = the wrap-up's\n * run id) and never deletes them: the row is still the timeline of what was\n * known at 04:43. This field carries that marker, and the record view and the\n * assistant panel render only the rows where it is `null`.\n */\n readonly supersededBy: string | null;\n /**\n * WHICH TRANSPORT DELIVERED THIS COPY (MRI-A12). The same durable row reaches\n * a signed-in member twice — once as a `meet_notes` row over Postgres Changes\n * (`\"record\"`) and once as a `matrx.meet.note` packet on the media plane\n * (`\"room\"`), which is the ONLY copy a session-less guest can receive, because\n * `anon` holds no grant on the table (MRI-A10).\n *\n * They carry the same id and the same words, so the store renders one note.\n * Where they could ever disagree, `\"record\"` wins and `\"room\"` never overwrites\n * it — the database is the record and the packet is the courtesy copy. That is\n * the same precedence captions and segments already follow (D16).\n */\n readonly source: \"record\" | \"room\";\n}\n\n/**\n * THE WRAP-UP, ANNOUNCED (MRI-A12). The summary, decisions and action items\n * arrive as ordinary notes; this says the pass that wrote them FINISHED, which\n * is the difference between \"no summary yet\" and \"no summary is coming\".\n *\n * 🚨 It reaches a screen only while the room still exists. `POST /v1/meet/end`\n * deletes the LiveKit room and the wrap-up runs afterwards, so on the ordinary\n * ending path nobody is in the room to be told — the post-meeting record view is\n * where the summary is read. A surface must therefore treat `null` as \"not\n * announced\", never as \"not written\".\n */\nexport interface WrapUpAnnouncement {\n readonly meetingId: MeetingId;\n /** The `meet_notes` ids the pass wrote, in the order it wrote them. */\n readonly noteIds: readonly string[];\n /** How many durable transcript segments it summarized. */\n readonly segmentCount: number;\n readonly at: string;\n}\n\n/**\n * THE NOTE-TAKER'S STATE, as the meeting row records it\n * (`meet_meetings.metadata.note_taker.state`, MRI-A2). Five values and no\n * spinner: a surface renders the state it is in, or the server's refusal.\n *\n * - `absent` — nobody summoned it. The control offers to.\n * - `joining` — dispatched; it has not entered the room yet.\n * - `transcribing` — the server recorded active transcription and the exact\n * deterministic actor is present in the room.\n * - `handoff_pending` — a row that said transcribing no longer has that exact\n * actor in the room. The next state and any missed audio are not inferred.\n * - `ended` — the recorded note-taker stopped. The cause is not inferred.\n */\nexport type NoteTakerState =\n | \"absent\"\n | \"joining\"\n | \"transcribing\"\n | \"handoff_pending\"\n | \"ended\";\n\n/** The lifecycle of a 1:1 or ad-hoc group call (R2). */\nexport type CallState =\n | \"idle\"\n | \"dialing\"\n | \"ringing\"\n | \"connecting\"\n | \"active\"\n | \"declined\"\n | \"missed\"\n | \"busy\"\n | \"cancelled\"\n | \"ended\"\n | \"failed\";\n\nexport interface CallInvite {\n readonly id: CallId;\n readonly organizationId: OrganizationId;\n readonly roomName: RoomName;\n readonly mode: CallMode;\n readonly callerUserId: UserId;\n readonly callerName: string;\n readonly callerAvatarUrl: string | null;\n readonly calleeUserIds: readonly UserId[];\n /** The durable conversation the invite was delivered into, if any. */\n readonly conversationId: string | null;\n readonly createdAt: string;\n readonly expiresAt: string;\n readonly state: CallState;\n readonly declineMessage: string | null;\n}\n\n/** A person the UI can call. Deliberately minimal: hosts already have this. */\nexport interface CallablePerson {\n readonly userId: UserId;\n readonly displayName: string;\n readonly avatarUrl: string | null;\n}\n\nexport type StageLayout = \"grid\" | \"speaker\" | \"sidebar\";\n","/**\n * THE CALL CENTER — ringing, answering, and the six ways a call ends badly.\n *\n * A call reaches you on whatever surface you are on (R2), which is why this is\n * mounted by the provider and not by a call page. It is also why delivery is\n * DUAL by design, not by belt-and-braces nervousness:\n *\n * - **The durable leg** is the invite ROW plus its Postgres Changes event. It\n * survives a reload, a late-joining tab, and a dropped socket, and it is what\n * makes a missed call a fact rather than a lost packet.\n * - **The instant leg** is a broadcast on the callee's user channel, which\n * arrives without a database round trip.\n *\n * Both are deduplicated on the invite id, so a call rings ONCE however it\n * arrives. Neither is a fallback for the other: removing the durable leg loses\n * calls, and removing the instant leg makes ringing feel slow.\n *\n * 🚨 THE FOUR RULES THAT MAKE RINGING SURVIVABLE\n *\n * 1. **A ring always ends.** Every outgoing call arms a timeout that writes\n * `missed`. A ring with no terminal state is a phone that never stops.\n * 2. **Answering on one device stops every other.** The `settled` signal on\n * your OWN user channel silences the other tabs. Without it, answering on a\n * laptop leaves a phone ringing in the room.\n * 3. **Busy is answered, not ignored.** Being in an active call auto-declines\n * with `busy`, so the caller learns something instead of ringing out.\n * 4. **The state machine is a MACHINE.** Transitions are validated: a\n * `declined` call cannot become `active` because a late accept arrived.\n */\n\nimport type { ChannelHandle, RealtimeManager } from \"@ai-matrx/realtime\";\nimport { MEET_EVENTS, userTopic } from \"./channels\";\nimport { MeetError } from \"./errors\";\nimport type { MeetRepository } from \"./repository\";\nimport type { MeetStore } from \"./store\";\nimport {\n asCallId,\n asRoomName,\n type CallId,\n type CallInvite,\n type CallMode,\n type CallState,\n type MeetIdentity,\n type RoomName,\n type UserId,\n} from \"./types\";\n\n/** Which states may follow which. An invalid transition throws, never silently applies. */\nconst TRANSITIONS: Readonly<Record<CallState, readonly CallState[]>> = {\n idle: [\"dialing\", \"ringing\"],\n dialing: [\"ringing\", \"connecting\", \"cancelled\", \"declined\", \"busy\", \"missed\", \"failed\"],\n ringing: [\"connecting\", \"declined\", \"busy\", \"missed\", \"cancelled\", \"failed\"],\n connecting: [\"active\", \"failed\", \"ended\"],\n active: [\"ended\", \"failed\"],\n declined: [],\n missed: [],\n busy: [],\n cancelled: [],\n ended: [],\n failed: [],\n};\n\nexport function canTransition(from: CallState, to: CallState): boolean {\n return TRANSITIONS[from].includes(to);\n}\n\nexport interface CallCenterOptions {\n manager: RealtimeManager;\n repository: MeetRepository;\n store: MeetStore;\n identity: MeetIdentity;\n /** Ring for this long before the call is `missed`. Org knob, not a constant. */\n ringTimeoutMs?: number | undefined;\n onIncoming?: ((invite: CallInvite) => void) | undefined;\n onSettled?: ((invite: CallInvite) => void) | undefined;\n onDiagnostic?: ((event: { level: \"info\" | \"warn\" | \"error\"; message: string; remedy?: string }) => void) | undefined;\n timers?: {\n setTimeout: (run: () => void, ms: number) => unknown;\n clearTimeout: (handle: unknown) => void;\n now: () => number;\n };\n}\n\nexport interface CallCenter {\n /** Subscribe to this user's calling channel. Call once, from the provider. */\n start(): Promise<void>;\n /** Ring someone. Returns the invite the UI shows as \"calling…\". */\n call(args: {\n people: readonly UserId[];\n mode: CallMode;\n conversationId?: string | undefined;\n }): Promise<CallInvite>;\n accept(id: CallId, mode: CallMode): Promise<CallInvite>;\n decline(id: CallId, message?: string): Promise<CallInvite>;\n cancel(id: CallId): Promise<CallInvite>;\n /** Every invite currently ringing this device. */\n incoming(): readonly CallInvite[];\n outgoing(): CallInvite | null;\n /** Feed a ring that arrived through another path (a messaging action chip). */\n ingest(invite: CallInvite): void;\n dispose(): void;\n}\n\nconst DEFAULT_RING_TIMEOUT_MS = 45_000;\n\nexport function createCallCenter(options: CallCenterOptions): CallCenter {\n const { manager, repository, identity } = options;\n const timers = options.timers ?? {\n setTimeout: (run, ms) => setTimeout(run, ms),\n clearTimeout: (handle) => clearTimeout(handle as ReturnType<typeof setTimeout>),\n now: () => Date.now(),\n };\n const ringTimeoutMs = options.ringTimeoutMs ?? DEFAULT_RING_TIMEOUT_MS;\n\n const incoming = new Map<CallId, CallInvite>();\n const timeouts = new Map<CallId, unknown>();\n let outgoing: CallInvite | null = null;\n let channel: ChannelHandle | null = null;\n\n /**\n * Send-only handles on OTHER people's user channels.\n *\n * 🚨 CACHED AND CLOSED, deliberately. Since `@ai-matrx/realtime` 0.2.0 a\n * channel is ref-counted per DECLARED topic, so `manager.open(...).send(...)`\n * without a matching `close()` increments a refcount that is never released —\n * a leaked subscription per ring, forever. One handle per peer, all closed on\n * dispose.\n */\n const outbound = new Map<string, ChannelHandle>();\n\n function to(userId: UserId): ChannelHandle {\n const topic = userTopic(userId);\n const existing = outbound.get(topic);\n if (existing !== undefined) return existing;\n const opened = manager.open({ topic });\n outbound.set(topic, opened);\n return opened;\n }\n\n function report(level: \"info\" | \"warn\" | \"error\", message: string, remedy?: string): void {\n options.onDiagnostic?.(remedy === undefined ? { level, message } : { level, message, remedy });\n }\n\n function requireUser(operation: string): UserId {\n if (identity.userId === null) {\n throw new MeetError(\n \"forbidden\",\n `${operation}: a guest cannot place or receive calls`,\n \"Guests join meetings by link (D6); calling requires an account. Render the join-by-\" +\n \"link path instead of a call button for guest identities.\",\n );\n }\n return identity.userId;\n }\n\n function clearRing(id: CallId): void {\n const handle = timeouts.get(id);\n if (handle !== undefined) {\n timers.clearTimeout(handle);\n timeouts.delete(id);\n }\n }\n\n function settleLocal(invite: CallInvite): void {\n clearRing(invite.id);\n incoming.delete(invite.id);\n if (outgoing !== null && outgoing.id === invite.id) outgoing = invite;\n options.onSettled?.(invite);\n }\n\n function ingest(invite: CallInvite): void {\n // ONE ring per invite, whichever leg arrived first.\n if (incoming.has(invite.id)) return;\n if (invite.state !== \"ringing\" && invite.state !== \"dialing\") return;\n if (identity.userId === null) return;\n if (invite.callerUserId === identity.userId) return;\n\n // RULE 3: busy is ANSWERED. The caller learns why rather than ringing out.\n const phase = options.store.snapshot().phase;\n if (phase === \"connected\" || phase === \"connecting\" || phase === \"reconnecting\") {\n void repository\n .settleCallInvite(invite.id, \"busy\", null)\n .then((settled) => {\n // The CALLER is who needs to know. Sending this on my own topic\n // would tell my other devices something they already worked out and\n // leave the caller ringing out into silence.\n to(settled.callerUserId).send(MEET_EVENTS.settled, settled);\n })\n .catch((error: unknown) => {\n report(\"warn\", `meet.calls: could not report busy — ${String(error)}`,\n \"The caller will ring out and see a missed call. Harmless, but the busy signal \" +\n \"is what makes a second call feel intentional.\");\n });\n return;\n }\n\n incoming.set(invite.id, { ...invite, state: \"ringing\" });\n options.onIncoming?.(invite);\n // RULE 1: every ring ends. Even if the caller vanishes mid-ring.\n timeouts.set(\n invite.id,\n timers.setTimeout(() => {\n const held = incoming.get(invite.id);\n if (held === undefined) return;\n settleLocal({ ...held, state: \"missed\" });\n }, ringTimeoutMs),\n );\n }\n\n return {\n async start() {\n const me = requireUser(\"meet.calls.start\");\n channel = manager.open({\n topic: userTopic(me),\n broadcast: [\n {\n event: MEET_EVENTS.ring,\n onMessage: (message) => {\n ingest(message.data as CallInvite);\n },\n },\n {\n event: MEET_EVENTS.cancel,\n onMessage: (message) => {\n const invite = message.data as CallInvite;\n const held = incoming.get(invite.id);\n if (held === undefined) return;\n settleLocal({ ...held, state: \"cancelled\" });\n },\n },\n {\n event: MEET_EVENTS.settled,\n onMessage: (message) => {\n // RULE 2: answered elsewhere. Stop ringing HERE.\n const invite = message.data as CallInvite;\n const held = incoming.get(invite.id);\n if (held !== undefined) settleLocal(invite);\n },\n },\n ],\n postgresChanges: [\n {\n event: \"INSERT\",\n schema: repository.schema,\n table: repository.tables.invites,\n filter: `callee_ids=cs.{${me}}`,\n rowId: (row) => (typeof row[\"id\"] === \"string\" ? row[\"id\"] : undefined),\n onChange: (delivery) => {\n if (delivery.row === null) return;\n ingest(repository.projectInvite(delivery.row));\n },\n },\n {\n event: \"UPDATE\",\n schema: repository.schema,\n table: repository.tables.invites,\n filter: `callee_ids=cs.{${me}}`,\n rowId: (row) => (typeof row[\"id\"] === \"string\" ? row[\"id\"] : undefined),\n onChange: (delivery) => {\n if (delivery.row === null) return;\n const invite = repository.projectInvite(delivery.row);\n if (invite.state !== \"ringing\" && invite.state !== \"dialing\") {\n const held = incoming.get(invite.id);\n if (held !== undefined) settleLocal(invite);\n }\n },\n },\n ],\n // THE BACKFILL DOOR. Realtime has no replay: a socket that dropped for\n // 20 seconds must re-read, or a call placed during the gap rings on the\n // caller's screen and nowhere else.\n onBackfill: async () => {\n const pending = await repository.pendingInvites(me);\n for (const invite of pending) ingest(invite);\n },\n });\n const pending = await repository.pendingInvites(me);\n for (const invite of pending) ingest(invite);\n },\n\n async call({ people, mode, conversationId }) {\n const me = requireUser(\"meet.calls.call\");\n if (people.length === 0) {\n throw new MeetError(\n \"misconfigured\",\n \"meet.calls.call: no callees\",\n \"Pass at least one user id. An empty call would create a room nobody is invited to.\",\n );\n }\n // The room name is minted CLIENT-SIDE and is opaque: the server validates\n // membership when it mints the token, so a guessed room name buys nothing.\n const roomName: RoomName = asRoomName(\n `call-${me}-${timers.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`,\n );\n const invite = await repository.createCallInvite({\n roomName,\n mode,\n callerUserId: me,\n callerName: identity.displayName,\n callerAvatarUrl: identity.avatarUrl,\n calleeUserIds: people,\n organizationId: identity.organizationId,\n conversationId: conversationId ?? null,\n expiresAt: new Date(timers.now() + ringTimeoutMs).toISOString(),\n });\n outgoing = invite;\n\n // The instant leg. The durable leg already happened — the row is written.\n for (const callee of people) {\n to(callee).send(MEET_EVENTS.ring, invite);\n }\n timeouts.set(\n invite.id,\n timers.setTimeout(() => {\n if (outgoing?.id !== invite.id) return;\n void repository\n .settleCallInvite(invite.id, \"missed\", null)\n .then((settled) => {\n outgoing = settled;\n options.onSettled?.(settled);\n })\n .catch(() => undefined);\n }, ringTimeoutMs),\n );\n return invite;\n },\n\n async accept(id, mode) {\n const held = incoming.get(id);\n if (held !== undefined && !canTransition(held.state, \"connecting\")) {\n throw new MeetError(\n \"conflict\",\n `meet.calls.accept: this call is already ${held.state}`,\n \"A late accept must not resurrect a settled call. Close the ringing UI; the caller \" +\n \"has already moved on.\",\n );\n }\n const settled = await repository.settleCallInvite(id, \"connecting\", null);\n settleLocal(settled);\n // Tell my OTHER devices to stop ringing, and the caller to stop waiting.\n channel?.send(MEET_EVENTS.settled, settled);\n to(settled.callerUserId).send(MEET_EVENTS.settled, { ...settled, mode });\n return settled;\n },\n\n async decline(id, message) {\n const settled = await repository.settleCallInvite(id, \"declined\", message ?? null);\n settleLocal(settled);\n channel?.send(MEET_EVENTS.settled, settled);\n to(settled.callerUserId).send(MEET_EVENTS.settled, settled);\n return settled;\n },\n\n async cancel(id) {\n const settled = await repository.settleCallInvite(id, \"cancelled\", null);\n clearRing(id);\n if (outgoing?.id === id) outgoing = settled;\n for (const callee of settled.calleeUserIds) {\n to(callee).send(MEET_EVENTS.cancel, settled);\n }\n return settled;\n },\n\n incoming: () => [...incoming.values()],\n outgoing: () => outgoing,\n ingest,\n\n dispose() {\n for (const id of [...timeouts.keys()]) clearRing(asCallId(id));\n incoming.clear();\n for (const handle of outbound.values()) handle.close();\n outbound.clear();\n channel?.close();\n channel = null;\n },\n };\n}\n","/**\n * DEVICE MANAGEMENT — the part users blame the product for.\n *\n * Every rule here exists because it is a support ticket somewhere:\n *\n * - **Labels are empty until permission is granted.** `enumerateDevices()`\n * happily returns three cameras with blank labels before the prompt. A picker\n * rendering \"Camera 1 / Camera 2\" is the classic symptom; we report\n * `labelsHidden` so the UI can say *why* instead.\n * - **A remembered device can vanish.** Unplug a headset between meetings and a\n * stored `deviceId` produces `OverconstrainedError`. The manager falls back to\n * the system default AND SAYS SO — a silent fallback is how someone joins on\n * the laptop mic while believing they are on their headset.\n * - **Selections persist per KIND, per device.** Injected storage (C10:\n * persistence-injected — this package's core purpose is not storage), with a\n * memory fallback that announces itself rather than pretending to be durable.\n * - **Enumeration is repeated on `devicechange`.** A picker that lists what was\n * plugged in at mount is wrong within seconds of a headset arriving.\n */\n\nimport { MeetError, normalizeDeviceError } from \"./errors\";\n\nexport type DeviceKind = \"audioinput\" | \"videoinput\" | \"audiooutput\";\n\nexport interface MeetDevice {\n readonly deviceId: string;\n readonly kind: DeviceKind;\n readonly label: string;\n}\n\nexport interface DeviceSnapshot {\n readonly devices: Readonly<Record<DeviceKind, readonly MeetDevice[]>>;\n readonly selected: Readonly<Record<DeviceKind, string | null>>;\n /** True when the browser is hiding labels because permission was not granted. */\n readonly labelsHidden: boolean;\n readonly permission: \"unknown\" | \"granted\" | \"denied\";\n /** Set when a remembered device was gone and we fell back. Shown, not swallowed. */\n readonly fallbackNotice: string | null;\n}\n\nexport interface DeviceStorage {\n read(): Record<string, string>;\n write(value: Record<string, string>): void;\n readonly durable: boolean;\n}\n\nexport interface MediaDevicesLike {\n enumerateDevices(): Promise<\n readonly { deviceId: string; kind: string; label: string }[]\n >;\n getUserMedia(constraints: { audio?: unknown; video?: unknown }): Promise<{\n getTracks(): readonly { stop(): void }[];\n }>;\n addEventListener?: ((type: \"devicechange\", handler: () => void) => void) | undefined;\n removeEventListener?: ((type: \"devicechange\", handler: () => void) => void) | undefined;\n}\n\nexport interface DeviceManagerOptions {\n media: MediaDevicesLike;\n storage?: DeviceStorage | undefined;\n onChange?: ((snapshot: DeviceSnapshot) => void) | undefined;\n}\n\nexport interface DeviceManager {\n /**\n * 🚨 THE SAME REFERENCE until something actually changes. This is a\n * `useSyncExternalStore` `getSnapshot` source (see `useDeviceSnapshot`), and\n * React compares snapshots by IDENTITY: a fresh object literal per call makes\n * every render report a change, which React reports as *\"The result of\n * getSnapshot should be cached\"* and then kills the tree with *\"Maximum\n * update depth exceeded\"*. `createMeetStore()` has always held this contract;\n * 0.2.0 shipped without it here and every room crashed at `<PreJoin>`.\n */\n snapshot(): DeviceSnapshot;\n /** Enumerate without prompting. Labels may be hidden; that is reported. */\n refresh(): Promise<DeviceSnapshot>;\n /** Prompt, then enumerate with real labels. The pre-join screen calls this. */\n requestPermission(kinds: { audio: boolean; video: boolean }): Promise<DeviceSnapshot>;\n select(kind: DeviceKind, deviceId: string): DeviceSnapshot;\n /** The id to actually use — the remembered one, or the default when it is gone. */\n resolve(kind: DeviceKind): string | null;\n subscribe(listener: (snapshot: DeviceSnapshot) => void): () => void;\n dispose(): void;\n}\n\nconst KINDS: readonly DeviceKind[] = [\"audioinput\", \"videoinput\", \"audiooutput\"];\n\nfunction isDeviceKind(value: string): value is DeviceKind {\n return value === \"audioinput\" || value === \"videoinput\" || value === \"audiooutput\";\n}\n\n/** localStorage when it exists; memory otherwise — and it says which. */\nexport function createWebDeviceStorage(key = \"mx.meet.devices\"): DeviceStorage {\n const store = (globalThis as { localStorage?: Storage }).localStorage;\n if (store === undefined) return createMemoryDeviceStorage();\n return {\n durable: true,\n read() {\n try {\n const raw = store.getItem(key);\n if (raw === null) return {};\n const parsed: unknown = JSON.parse(raw);\n return typeof parsed === \"object\" && parsed !== null\n ? (parsed as Record<string, string>)\n : {};\n } catch {\n return {};\n }\n },\n write(value) {\n try {\n store.setItem(key, JSON.stringify(value));\n } catch {\n // A full or blocked storage must not break joining a call.\n }\n },\n };\n}\n\nexport function createMemoryDeviceStorage(): DeviceStorage {\n let value: Record<string, string> = {};\n return {\n durable: false,\n read: () => value,\n write: (next) => {\n value = next;\n },\n };\n}\n\nexport function createDeviceManager(options: DeviceManagerOptions): DeviceManager {\n const storage = options.storage ?? createMemoryDeviceStorage();\n const listeners = new Set<(snapshot: DeviceSnapshot) => void>();\n const stored = storage.read();\n\n let devices: Record<DeviceKind, readonly MeetDevice[]> = {\n audioinput: [],\n videoinput: [],\n audiooutput: [],\n };\n let selected: Record<DeviceKind, string | null> = {\n audioinput: stored[\"audioinput\"] ?? null,\n videoinput: stored[\"videoinput\"] ?? null,\n audiooutput: stored[\"audiooutput\"] ?? null,\n };\n let labelsHidden = true;\n let permission: DeviceSnapshot[\"permission\"] = \"unknown\";\n let fallbackNotice: string | null = null;\n\n // 🚨 THE MEMOIZED SNAPSHOT. `current` IS the snapshot; readers get this exact\n // object until `commit()` replaces it, which happens only when one of the\n // five fields above actually moved. See the `DeviceManager.snapshot` doc\n // comment for the crash this prevents.\n let current: DeviceSnapshot = {\n devices,\n selected,\n labelsHidden,\n permission,\n fallbackNotice,\n };\n\n function snapshot(): DeviceSnapshot {\n return current;\n }\n\n /** Rebuild the snapshot from the current state. Call after ANY mutation. */\n function commit(): DeviceSnapshot {\n current = { devices, selected, labelsHidden, permission, fallbackNotice };\n return current;\n }\n\n function emit(): DeviceSnapshot {\n const next = commit();\n options.onChange?.(next);\n for (const listener of listeners) listener(next);\n return next;\n }\n\n async function enumerate(): Promise<DeviceSnapshot> {\n let raw: readonly { deviceId: string; kind: string; label: string }[];\n try {\n raw = await options.media.enumerateDevices();\n } catch (error) {\n throw normalizeDeviceError(error, \"meet.enumerateDevices\");\n }\n const grouped: Record<DeviceKind, MeetDevice[]> = {\n audioinput: [],\n videoinput: [],\n audiooutput: [],\n };\n let anyLabel = false;\n for (const device of raw) {\n if (!isDeviceKind(device.kind)) continue;\n if (device.label.length > 0) anyLabel = true;\n grouped[device.kind].push({\n deviceId: device.deviceId,\n kind: device.kind,\n label: device.label,\n });\n }\n devices = grouped;\n labelsHidden = !anyLabel && raw.length > 0;\n\n // THE VANISHED-DEVICE FALLBACK. A remembered id that is no longer present\n // is dropped to the system default, and the notice is part of the snapshot\n // so the UI can say \"your headset is unplugged — using the built-in mic\".\n const lost: string[] = [];\n for (const kind of KINDS) {\n const current = selected[kind];\n if (current === null) continue;\n if (!grouped[kind].some((device) => device.deviceId === current)) {\n selected = { ...selected, [kind]: null };\n lost.push(kind);\n }\n }\n fallbackNotice =\n lost.length === 0\n ? null\n : `A remembered ${lost.join(\" and \")} device is no longer connected — using the ` +\n \"system default. Pick another in the device menu.\";\n return emit();\n }\n\n const onDeviceChange = (): void => {\n void enumerate();\n };\n options.media.addEventListener?.(\"devicechange\", onDeviceChange);\n\n return {\n snapshot,\n refresh: enumerate,\n async requestPermission(kinds) {\n if (!kinds.audio && !kinds.video) {\n throw new MeetError(\n \"misconfigured\",\n \"meet.requestPermission: asked for neither audio nor video\",\n \"Request at least one kind. Prompting for nothing silently resolves and leaves \" +\n \"labels hidden, which looks like a broken picker.\",\n );\n }\n try {\n const stream = await options.media.getUserMedia({\n ...(kinds.audio ? { audio: true } : {}),\n ...(kinds.video ? { video: true } : {}),\n });\n // 🚨 STOP THE PROBE STREAM. Holding it keeps the camera light on and,\n // on Windows, makes the real join fail with NotReadableError — the\n // device is busy with our own probe.\n for (const track of stream.getTracks()) track.stop();\n permission = \"granted\";\n } catch (error) {\n permission = \"denied\";\n emit();\n throw normalizeDeviceError(error, \"meet.requestPermission\");\n }\n return enumerate();\n },\n select(kind, deviceId) {\n selected = { ...selected, [kind]: deviceId };\n fallbackNotice = null;\n storage.write({\n ...storage.read(),\n [kind]: deviceId,\n });\n return emit();\n },\n resolve(kind) {\n const current = selected[kind];\n if (current !== null && devices[kind].some((device) => device.deviceId === current)) {\n return current;\n }\n return devices[kind][0]?.deviceId ?? null;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n dispose() {\n options.media.removeEventListener?.(\"devicechange\", onDeviceChange);\n listeners.clear();\n },\n };\n}\n","/**\n * WHO SAID THAT — one answer, every surface, both lanes (MRI-A16).\n *\n * 🚨 **A RAW LIVEKIT IDENTITY IS NEVER A PERSON'S NAME.** On production\n * 2026-09-09 the host's caption rail read *\"Ada Lovelace: I planted a marigold\n * in the courtyard\"* and the guest's — the same meeting, the same second —\n * read *\"guest:c8-spk-1\"*, because the host resolved the name from the durable\n * rows it can read and the guest had no fallback at all and printed the token\n * (MRI-C8). Two surfaces disagreeing about who is speaking is worse than either\n * one being ugly: a person reading the transcript cannot tell whether those are\n * one speaker or two.\n *\n * The cure is that nothing resolves a name for itself. Every source that\n * happens to KNOW a name teaches this book — the LiveKit roster, a durable\n * `meet_transcript_segments` row, a durable `meet_participants` row, a chat\n * message, our own identity — and every surface asks it. Three rules:\n *\n * 1. **A name is learned, never unlearned.** Someone who leaves the room keeps\n * the name they had; a caption that lands after them still says who spoke.\n * This is the \"last known name\" rule, and it is why the book is a store\n * field rather than a derivation over the current roster.\n * 2. **An identity is not a name.** `learn` refuses a \"name\" that is the\n * identity itself — which is exactly what the LiveKit roster hands back for\n * a participant whose token carried no name, and exactly how the token got\n * onto the screen in the first place.\n * 3. **When nobody knows, SAY nobody knows.** `displayNameFor` answers with an\n * honest placeholder — \"Unnamed guest\" / \"Unnamed participant\" — never a\n * token, and never an invented name. The placeholder is deliberately not\n * unique, so surfaces that must keep two unnamed people apart group by\n * IDENTITY rather than by the rendered name.\n */\n\nimport type { ParticipantIdentity } from \"./types\";\n\n/** Identity → the best display name anything has ever known for it. */\nexport type NameBook = Readonly<Record<string, string>>;\n\n/** A guest's identity is minted `guest:<something>` by the token route. */\nexport function isGuestIdentity(identity: ParticipantIdentity | string): boolean {\n return String(identity).startsWith(\"guest:\");\n}\n\n/**\n * An AGENT's identity is minted `agent:<capability>:<meeting>` by the server\n * (`services/meet/worker.py`). An agent is never an anonymous \"participant\":\n * it is a product with a name, and a room that cannot say which product is\n * listening has failed the consent notice it is required to carry (D10).\n */\nexport function isAgentIdentity(identity: ParticipantIdentity | string): boolean {\n return String(identity).startsWith(\"agent:\");\n}\n\n/** The note-taker's product name — `services/meet/worker.py::AGENT_DISPLAY_NAME`. */\nexport const NOTE_TAKER_PRODUCT_NAME = \"Matrx note-taker\";\n/** Any other Matrx agent whose dispatch carried no name. */\nexport const AGENT_PRODUCT_NAME = \"Matrx agent\";\n/** Somebody in the room whose name nothing has ever known. */\nexport const UNNAMED_GUEST = \"Unnamed guest\";\n/** The same, for a participant whose identity is not a guest token. */\nexport const UNNAMED_PARTICIPANT = \"Unnamed participant\";\n\n/**\n * The strings THIS MODULE invents when nobody knows a name. They are answers,\n * never facts: `isRealName` refuses them, so a placeholder can never be learned\n * as somebody's name and can never outrank a real name that arrives later.\n *\n * 🚨 This is what makes the roster safe to route through the book. A roster\n * event projects \"Unnamed guest\" for a nameless participant; a durable\n * transcript row then teaches \"Ada Lovelace\"; without this rule the placeholder\n * — a perfectly ordinary-looking string — would win, and the screen would keep\n * saying \"Unnamed guest\" about somebody the meeting plainly knows.\n */\nconst PLACEHOLDER_NAMES: readonly string[] = [\n NOTE_TAKER_PRODUCT_NAME,\n AGENT_PRODUCT_NAME,\n UNNAMED_GUEST,\n UNNAMED_PARTICIPANT,\n];\n\n/** Is this string one of the placeholders this module produces? */\nexport function isPlaceholderName(name: string | null | undefined): boolean {\n return typeof name === \"string\" && PLACEHOLDER_NAMES.includes(name.trim());\n}\n\n/** What an identity is called when NOTHING knows a name for it. Never a token. */\nexport function placeholderNameFor(identity: ParticipantIdentity | string): string {\n const key = String(identity);\n if (isAgentIdentity(key)) {\n return key.startsWith(\"agent:note_taker:\") || key.startsWith(\"agent:note-taker\")\n ? NOTE_TAKER_PRODUCT_NAME\n : AGENT_PRODUCT_NAME;\n }\n return isGuestIdentity(key) ? UNNAMED_GUEST : UNNAMED_PARTICIPANT;\n}\n\n/**\n * Would this string be a real name for this identity? A name equal to the\n * identity is the roster's way of saying it has none.\n */\nexport function isRealName(\n identity: ParticipantIdentity | string,\n name: string | null | undefined,\n): boolean {\n if (typeof name !== \"string\") return false;\n const trimmed = name.trim();\n if (trimmed.length === 0) return false;\n if (trimmed === String(identity)) return false;\n // Our own answer is not new information. See PLACEHOLDER_NAMES.\n if (isPlaceholderName(trimmed)) return false;\n return true;\n}\n\n/**\n * Teach the book one identity's name. Returns the SAME book when nothing was\n * learned, so a store commit can be skipped rather than waking every subscriber\n * on every caption.\n */\nexport function learnName(\n book: NameBook,\n identity: ParticipantIdentity | string,\n name: string | null | undefined,\n): NameBook {\n const key = String(identity);\n if (key.length === 0) return book;\n if (!isRealName(key, name)) return book;\n const learned = (name as string).trim();\n if (book[key] === learned) return book;\n return { ...book, [key]: learned };\n}\n\n/** Teach the book several at once — a roster replace, or a durable read. */\nexport function learnNames(\n book: NameBook,\n entries: readonly {\n identity: ParticipantIdentity | string;\n displayName?: string | null | undefined;\n }[],\n): NameBook {\n let next = book;\n for (const entry of entries) next = learnName(next, entry.identity, entry.displayName);\n return next;\n}\n\n/**\n * The name a surface renders for `identity`. Never a raw token, never invented.\n *\n * `preferred` is what the arriving thing itself claimed (a caption's roster\n * lookup, a durable row's `speaker` column); it wins when it is a real name,\n * because it is the freshest, and teaches the book on its way past.\n */\nexport function displayNameFor(\n book: NameBook,\n identity: ParticipantIdentity | string,\n preferred?: string | null | undefined,\n): string {\n const key = String(identity);\n if (isRealName(key, preferred)) return (preferred as string).trim();\n const known = book[key];\n if (known !== undefined) return known;\n // NOBODY KNOWS, AND THAT IS WHAT IT SAYS. A person reading this can tell the\n // difference between \"someone whose name we never learned\" and a name.\n return placeholderNameFor(key);\n}\n","/**\n * RECORDING — LiveKit Egress, host-controlled, consent-enforced (R3/R5).\n *\n * 🚨 **CONSENT IS NOT OPTIONAL AND NOT A PROP.** There is no\n * `showRecordingIndicator={false}`. Recording a person without telling them is\n * illegal in a two-party-consent jurisdiction and is indefensible everywhere\n * else, so the indicator and the join-time notice are properties of the\n * package, not decisions a consumer gets to make. The only knob is the org's\n * `recordingPolicy` — disabled / host-controlled / always-on — which decides\n * whether recording may happen at all, never whether people are told.\n *\n * 🚨 **THE RECORDING BELONGS TO THE PLATFORM, NOT TO LIVEKIT.** The server\n * lands the artifact in the platform files system and returns a FILE ID. A\n * provider URL would be an orphan the day the room is garbage collected — the\n * reason `RecordingRecord.fileId` is not `url`.\n *\n * The client half is small on purpose: start/stop are aidream calls (the API\n * secret never comes near a browser), and the truth about a recording arrives\n * from the server's webhook through the room channel. This module never\n * *guesses* that a recording started.\n */\n\nimport type { MeetApi } from \"./api\";\nimport { MeetError } from \"./errors\";\nimport type { MeetStore } from \"./store\";\nimport { MEET_ROUTES } from \"./tokens\";\nimport type {\n MeetingId,\n MeetingRecord,\n RecordingState,\n RoomName,\n UserId,\n} from \"./types\";\n\nexport interface RecordingControllerOptions {\n /** The ONE org-aware aidream client (MRI-A16). Owns base url and headers. */\n api: MeetApi;\n store: MeetStore;\n /** Announce the new state to everyone in the room (the indicator is for all). */\n announce?: ((state: RecordingState, by: UserId | null) => void) | undefined;\n /** Persist that this participant saw the notice. Consent is RECORDED (R5). */\n acknowledgeConsent?: ((meetingId: MeetingId) => Promise<void>) | undefined;\n}\n\nexport interface RecordingController {\n /** True when the org policy and the actor's role allow starting a recording. */\n canStart(meeting: MeetingRecord | null, isHost: boolean): boolean;\n start(args: { meetingId: MeetingId; roomName: RoomName; by: UserId }): Promise<void>;\n stop(args: { meetingId: MeetingId; by: UserId }): Promise<void>;\n /** The join-time notice text. One sentence, one place, every surface. */\n consentNotice(meeting: MeetingRecord | null): string | null;\n acknowledge(meetingId: MeetingId): Promise<void>;\n}\n\nexport function createRecordingController(\n options: RecordingControllerOptions,\n): RecordingController {\n async function post(route: string, body: Record<string, unknown>): Promise<void> {\n let response: Response;\n try {\n response = await options.api.request({\n path: route,\n method: \"POST\",\n // A GUEST CAN NEVER START OR STOP A RECORDING (R5) — refused here,\n // before the wire, with the same sentence the hidden control implies.\n requireAuth: true,\n operation: \"meet.recording\",\n body,\n });\n } catch (error) {\n if ((error as { code?: string }).code === \"session-unavailable\") {\n throw new MeetError(\n \"forbidden\",\n \"meet.recording: recording requires an authenticated host\",\n \"A guest can never start or stop a recording (R5). The control is hidden for guests.\",\n );\n }\n throw error;\n }\n if (response.status === 403) {\n throw new MeetError(\n \"forbidden\",\n \"meet.recording: the server refused this recording action\",\n \"The actor is not a host of this meeting, or the org policy is `disabled`. The server \" +\n \"is the authority; do not re-decide it on the client.\",\n );\n }\n if (!response.ok) {\n throw new MeetError(\n \"transport\",\n `meet.recording: the server returned ${response.status}`,\n \"Egress could not be controlled. The recording state stays where it was rather than \" +\n \"showing a recording indicator for a recording that is not running.\",\n );\n }\n }\n\n return {\n canStart(meeting, isHost) {\n if (meeting === null) return false;\n if (meeting.recordingPolicy === \"disabled\") return false;\n // `always-on` is started by the SERVER when the room opens; a host cannot\n // start (or stop) it, which is the point of the policy.\n if (meeting.recordingPolicy === \"always-on\") return false;\n return isHost;\n },\n\n async start({ meetingId, roomName, by }) {\n // OPTIMISTIC ONLY AS FAR AS \"starting\", and marked `\"local\"` so the\n // durable row overrules it the moment it lands (D16). The indicator turns\n // solid when the SERVER says the egress is running — never on a client's\n // hope, and never STUCK on that hope either: `meet_recordings` is\n // subscribed and `matrx.meet.recording` reaches the guests (MRI-A16).\n options.store.setRecording(\"starting\", by, \"local\");\n try {\n await post(MEET_ROUTES.recordingStart, {\n meeting_id: meetingId,\n room_name: roomName,\n });\n } catch (error) {\n options.store.setRecording(\"idle\", null, \"local\");\n throw error;\n }\n options.announce?.(\"starting\", by);\n },\n\n async stop({ meetingId, by }) {\n options.store.setRecording(\"stopping\", options.store.snapshot().recordingStartedBy, \"local\");\n try {\n await post(MEET_ROUTES.recordingStop, { meeting_id: meetingId });\n } catch (error) {\n options.store.setRecording(\n \"recording\",\n options.store.snapshot().recordingStartedBy,\n \"local\",\n );\n throw error;\n }\n options.announce?.(\"stopping\", by);\n },\n\n consentNotice(meeting) {\n if (meeting === null || meeting.recordingPolicy === \"disabled\") return null;\n if (meeting.recordingPolicy === \"always-on\") {\n return \"This meeting is recorded and transcribed automatically. By joining, you consent to being recorded.\";\n }\n return \"The host can record and transcribe this meeting. You will see a recording indicator whenever it is running.\";\n },\n\n async acknowledge(meetingId) {\n await options.acknowledgeConsent?.(meetingId);\n },\n };\n}\n\n/**\n * 🚨 IS A RECORDING IN FLIGHT RIGHT NOW? One definition (MRI-A16).\n *\n * The control used to ask `state === \"idle\"`, which was survivable only while\n * the store never learned any state but its own: the moment the DURABLE states\n * started arriving, a meeting whose first recording had finished sat on\n * `available` forever and the host could never start a second one — the Start\n * button simply stopped existing. `processing`, `available` and `failed` all\n * mean \"nothing is recording\"; only these three mean it is.\n */\nexport const RECORDING_IN_FLIGHT: readonly RecordingState[] = [\n \"starting\",\n \"recording\",\n \"stopping\",\n];\n\nexport function isRecordingInFlight(state: RecordingState): boolean {\n return RECORDING_IN_FLIGHT.includes(state);\n}\n\n/** The indicator's words. One definition, so no surface invents a softer one. */\nexport function recordingLabel(state: RecordingState): string | null {\n switch (state) {\n case \"starting\":\n return \"Starting recording…\";\n case \"recording\":\n return \"Recording\";\n case \"stopping\":\n return \"Stopping recording…\";\n case \"processing\":\n return \"Processing recording…\";\n case \"available\":\n return \"Recording ready\";\n case \"expired\":\n return \"Recording expired\";\n case \"failed\":\n return \"Recording failed\";\n default:\n return null;\n }\n}\n","/**\n * LISTEN-ONLY ATTENDANCE — being IN the room is never contingent on a device.\n *\n * 0.3.1 and every version before it enabled the microphone as the last step of\n * `connect()`, inside the same `try` as the join. So a denied, absent, or busy\n * microphone did not produce a muted participant — it threw, the join was\n * failed with a device remedy, and the user was dropped back to `<PreJoin>`\n * having never entered the meeting. The whole in-room surface (tiles, captions,\n * live notes, Q&A, the note-taker consent notice) was unreachable to anyone\n * without a working mic, which is ordinary: a locked-down laptop, a conference\n * room dial-in, a phone on a call, a browser profile that denies capture by\n * policy, or a person who simply wants to listen. Every competitor allows it.\n *\n * THE CLASS, and how it is closed here:\n *\n * 1. **Connecting and publishing are two different operations.** The engine\n * reaches `connected` the moment the transport is up. Media is attempted\n * AFTER that, per track, and a rejection never unwinds the join.\n * 2. **A track that could not be acquired is STATE, not an exception.** The\n * reason and its remedy — the browser's own, translated by\n * `normalizeDeviceError` — ride in the snapshot so the UI says WHY the mic\n * is off instead of showing a mute button that silently does nothing.\n * 3. **Enabling later runs the SAME code path.** `setMicrophoneEnabled(true)`\n * from the control bar records exactly what the join attempt records, so a\n * person who plugs in a headset mid-meeting is one click from speaking and\n * a person whose second attempt also fails gets the same honest sentence.\n * A separate \"retry\" path is how the two drift.\n * 4. **The notice is one sentence, defined once.** Both the package's own room\n * chrome and any host that renders its own read `listenOnlyNotice()`, so\n * there is no second wording to keep in sync.\n */\n\nimport type { MeetError } from \"./errors\";\n\n/** Why a local track is not publishing, in the browser's terms plus a remedy. */\nexport interface MediaUnavailable {\n readonly code: string;\n readonly message: string;\n readonly remedy: string;\n}\n\nexport interface LocalTrackState {\n /** True only when the track is actually published. Never optimistic. */\n readonly enabled: boolean;\n /**\n * Set when acquisition was ATTEMPTED and refused. `null` covers both \"on\"\n * and \"deliberately off\" — a user who unchecked the mic in pre-join is not\n * looking at an error, they are looking at a choice they made.\n */\n readonly unavailable: MediaUnavailable | null;\n}\n\nexport interface LocalMediaState {\n readonly microphone: LocalTrackState;\n readonly camera: LocalTrackState;\n}\n\nexport const IDLE_TRACK: LocalTrackState = { enabled: false, unavailable: null };\n\nexport const IDLE_MEDIA: LocalMediaState = {\n microphone: IDLE_TRACK,\n camera: IDLE_TRACK,\n};\n\nexport function unavailableFrom(error: MeetError): MediaUnavailable {\n return { code: error.code, message: error.message, remedy: error.remedy };\n}\n\n/**\n * THE SENTENCE. One definition, so the room chrome, a host's own chrome and the\n * tests cannot say three different things about the same fact.\n */\nexport const LISTEN_ONLY_NOTICE =\n \"You're attending without a microphone — others can't hear you\";\n\n/**\n * True when this participant is in the room and publishing no microphone —\n * whether the device was refused or simply turned off. Both are listen-only,\n * and both deserve the same honest line; only the REMEDY differs, and that\n * comes from `media.microphone.unavailable`.\n */\nexport function isListenOnly(media: LocalMediaState): boolean {\n return !media.microphone.enabled;\n}\n\n/**\n * The notice to render while in the room, or `null` when the mic is live.\n * Returns the plain sentence; the reason and remedy, when there is one, are\n * rendered beside it from `media.microphone.unavailable`.\n */\nexport function listenOnlyNotice(media: LocalMediaState): string | null {\n return isListenOnly(media) ? LISTEN_ONLY_NOTICE : null;\n}\n","/**\n * CAPTIONS ARE HINTS; SEGMENTS ARE TRUTH (D16).\n *\n * Two independent streams describe the same speech and they arrive out of order\n * with different identities:\n *\n * 1. **Captions** ride the LiveKit `lk.transcription` text stream, keyed by\n * `lk.segment_id`, interim-then-final, milliseconds behind the voice. They\n * exist so a person can READ the room live. Their `sender_identity` is\n * supplied by the publishing client and LiveKit does not validate it, so\n * nothing downstream — notes, Q&A, the wrap-up — may ever read them.\n * 2. **Records** are `communication.meet_transcript_segments` rows, written\n * server-side by the note-taker with a deterministic id (D6) and delivered\n * here by Postgres Changes. They are the meeting's transcript.\n *\n * The reconciliation below is what keeps the screen from saying everything\n * twice. A record REPLACES the caption it supersedes — matched by the caption\n * id the worker carries into the row, and failing that by speaker + text — and\n * a caption never overwrites a record, however late it lands.\n *\n * Everything here is a pure function over a list so the rules are provable\n * without a store, a socket, or a browser.\n */\n\nimport type { ParticipantIdentity, TranscriptSegment } from \"./types\";\n\n/** Comparable text: case, punctuation and spacing are not differences. */\nexport function normalizeSpoken(text: string): string {\n return text\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}]+/gu, \" \")\n .trim();\n}\n\nfunction supersedes(record: TranscriptSegment, caption: TranscriptSegment): boolean {\n if (caption.source !== \"caption\") return false;\n if (caption.identity !== record.identity) return false;\n if (record.captionId !== null && caption.captionId === record.captionId) return true;\n const left = normalizeSpoken(record.text);\n const right = normalizeSpoken(caption.text);\n if (left.length === 0 || right.length === 0) return false;\n // An interim caption is a PREFIX of what was finally said; a final caption and\n // its record usually differ only in punctuation. Both are the same utterance.\n return left === right || left.startsWith(right) || right.startsWith(left);\n}\n\n/**\n * A caption arrived. Interim replaces interim in place; a final never loses to a\n * late interim; a record is never touched.\n */\nexport function mergeCaption(\n list: readonly TranscriptSegment[],\n caption: TranscriptSegment,\n): readonly TranscriptSegment[] {\n const index = list.findIndex(\n (entry) => entry.captionId !== null && entry.captionId === caption.captionId,\n );\n if (index === -1) {\n // The record for this utterance may already be here (the row can beat the\n // caption on a slow media path). Do not draw the same sentence twice.\n if (list.some((entry) => entry.source === \"record\" && supersedes(entry, caption))) {\n return list;\n }\n return [...list, caption];\n }\n const existing = list[index];\n if (existing === undefined) return list;\n // TRUTH WINS. A caption cannot revert a durable row, and a late interim cannot\n // revert a final — that is a finished sentence visibly becoming a half-word.\n if (existing.source === \"record\") return list;\n if (existing.final && !caption.final) return list;\n return list.map((entry, position) => (position === index ? caption : entry));\n}\n\n/**\n * A durable row arrived. It replaces the caption it supersedes — in place, so\n * the line does not jump down the panel — or lands as a new line if no caption\n * ever showed it (a surface that joined late, or captions that never came).\n */\nexport function mergeRecord(\n list: readonly TranscriptSegment[],\n record: TranscriptSegment,\n): readonly TranscriptSegment[] {\n const byId = list.findIndex((entry) => entry.source === \"record\" && entry.id === record.id);\n if (byId !== -1) {\n const existing = list[byId];\n if (existing !== undefined && existing.text === record.text && existing.final === record.final) {\n return list;\n }\n return list.map((entry, position) => (position === byId ? record : entry));\n }\n const captionIndex = list.findIndex((entry) => supersedes(record, entry));\n if (captionIndex === -1) return [...list, record];\n return list.map((entry, position) => (position === captionIndex ? record : entry));\n}\n\n/** The transcript a person reads: chronological, and never an empty line. */\nexport function readableTranscript(\n list: readonly TranscriptSegment[],\n): readonly TranscriptSegment[] {\n return [...list]\n .filter((entry) => entry.text.trim().length > 0)\n .sort((left, right) => left.startedAt.localeCompare(right.startedAt));\n}\n\n/** Build a caption line from the media plane. */\nexport function captionSegment(args: {\n captionId: string;\n meetingId: TranscriptSegment[\"meetingId\"];\n identity: ParticipantIdentity;\n speaker: string;\n text: string;\n final: boolean;\n startedAt: string;\n}): TranscriptSegment {\n return {\n id: `caption:${args.captionId}`,\n meetingId: args.meetingId,\n identity: args.identity,\n speaker: args.speaker,\n text: args.text,\n startedAt: args.startedAt,\n final: args.final,\n source: \"caption\",\n captionId: args.captionId,\n };\n}\n","/**\n * THE ROOM SNAPSHOT — one immutable object the UI renders and nothing else.\n *\n * Deliberately NOT Redux, NOT a context full of `useState`, and NOT a bag of\n * refs: one store with `getSnapshot`/`subscribe` is exactly what\n * `useSyncExternalStore` wants, which is what makes tearing impossible when a\n * roster event and a speaker event land in the same tick.\n *\n * The rules encoded here:\n *\n * - **The roster is replaced wholesale, never patched.** The driver hands us\n * the full truth on every media event (see `room-driver.ts`); merging deltas\n * from six event sources is how a tile for someone who left stays on screen.\n * - **Ephemera EXPIRE.** Reactions and speaking flags are time-boxed in the\n * snapshot, so a dropped \"stop\" event cannot leave a permanent 🎉 or a\n * permanently-speaking ring. (Nothing here relies on receiving an end event.)\n * - **An interim transcript line is REPLACED in place by its final.** Appending\n * both is how a transcript ends up saying everything twice.\n */\n\nimport { displayNameFor, learnName, learnNames, type NameBook } from \"./names\";\nimport { isRecordingInFlight } from \"./recording\";\nimport { IDLE_MEDIA, type LocalMediaState, type LocalTrackState } from \"./attendance\";\nimport { ROLE_RANK } from \"./types\";\nimport type { NoteTakerRefusal } from \"./note-taker\";\nimport { mergeCaption, mergeRecord } from \"./transcript\";\nimport type {\n AdmissionState,\n ConnectionQuality,\n LobbyEntry,\n MeetParticipant,\n MeetingNote,\n MeetingRecord,\n ParticipantIdentity,\n ParticipantRole,\n RecordingSource,\n RecordingState,\n RoomPhase,\n StageLayout,\n TranscriptSegment,\n UserId,\n WrapUpAnnouncement,\n} from \"./types\";\n\nexport interface RoomChatMessage {\n readonly id: string;\n readonly identity: ParticipantIdentity;\n readonly displayName: string;\n readonly text: string;\n readonly at: string;\n /**\n * Set for a PRIVATE message: the one identity it was addressed to (from the\n * sender's side) or this participant (from the receiver's). Private messages\n * travel the data plane only and are never saved (Meet wave 2).\n */\n readonly to?: ParticipantIdentity | null | undefined;\n /** True once the server has SAVED it — a message everyone sees, late joiners too. */\n readonly saved?: boolean | undefined;\n /** A send the server refused, with its sentence. The message stays visible, marked. */\n readonly failed?: string | undefined;\n}\n\n/**\n * A HOST ACTED ON *ME* (Meet wave 2) — the server's own `matrx.meet.moderation`\n * packet, addressed to this participant. Rendered once, dismissible, in words.\n */\nexport interface ModerationNotice {\n readonly kind: \"muted\" | \"ask-unmute\" | \"removed\" | \"role\";\n readonly text: string;\n readonly at: number;\n}\n\n/** What this participant chose for their own media. Remembered per browser. */\nexport interface MediaEffects {\n readonly noiseSuppression: boolean;\n readonly background: \"none\" | \"blur\" | \"image\";\n readonly backgroundImage: string | null;\n}\n\nexport const DEFAULT_EFFECTS: MediaEffects = {\n noiseSuppression: true,\n background: \"none\",\n backgroundImage: null,\n};\n\nexport interface RoomReaction {\n readonly id: string;\n readonly identity: ParticipantIdentity;\n readonly emoji: string;\n readonly at: number;\n}\n\n/**\n * 🚨 WHAT THE SERVER GRANTED THIS JOINER, straight off the token response\n * (MRI-A11). It is placed in the snapshot the instant the token lands — before\n * the LiveKit roster exists at all — so a host's controls are correct on the\n * first frame of the room rather than one roster event later. The roster entry\n * for the local participant carries the SAME decision as a LiveKit attribute;\n * the two agree because one server statement produced both, and the UI reads\n * whichever has arrived.\n */\nexport interface MeetGrants {\n readonly role: ParticipantRole;\n readonly canRecord: boolean;\n readonly canPublish: boolean;\n readonly canSubscribe: boolean;\n}\n\n/** No token yet grants nothing. Never \"assume host until told otherwise\". */\nexport const NO_GRANTS: MeetGrants = {\n role: \"participant\",\n canRecord: false,\n canPublish: false,\n canSubscribe: false,\n};\n\nexport interface MeetSnapshot {\n readonly phase: RoomPhase;\n readonly meeting: MeetingRecord | null;\n readonly localIdentity: ParticipantIdentity | null;\n /** The server's word on what THIS joiner may do. See `MeetGrants`. */\n readonly grants: MeetGrants;\n readonly participants: readonly MeetParticipant[];\n readonly activeSpeakers: readonly ParticipantIdentity[];\n readonly pinned: ParticipantIdentity | null;\n readonly layout: StageLayout;\n readonly lobby: readonly LobbyEntry[];\n readonly locked: boolean;\n /**\n * 🚨 THE DURABLE `meet_recordings.state`, not a client's hope. Through 0.4.7\n * this only ever held what THIS browser optimistically patched — `starting`\n * on the click, `stopping` on the stop — so the indicator read \"Starting\n * recording…\" for the whole meeting while a perfectly healthy egress ran, and\n * \"Stopping recording…\" forever after (MRI-C8). The server's transitions\n * arrive on two transports now: the `meet_recordings` row for a member, and\n * a `matrx.meet.recording` room event for a guest, who has no database.\n */\n readonly recording: RecordingState;\n readonly recordingStartedBy: UserId | null;\n /**\n * WHICH transport last spoke, so the two cannot undo each other (D16). The\n * database wins: `\"record\"` is never overwritten by `\"room\"` or `\"local\"`.\n */\n readonly recordingSource: RecordingSource;\n /**\n * WHICH recording this state is about. It is what tells a LATE packet for a\n * finished recording apart from the FIRST packet of the next one — without\n * it, \"the database wins\" either blocks a second recording forever or lets a\n * stale packet drag a finished one back to `recording`.\n */\n readonly recordingId: string | null;\n readonly chat: readonly RoomChatMessage[];\n /** Whether the SAVED chat has been read for this meeting (late joiners see history). */\n readonly chatLoaded: boolean;\n /** Why the saved chat could not be read on join, in words — or null. */\n readonly chatHistoryError: string | null;\n readonly reactions: readonly RoomReaction[];\n /**\n * The participant a HOST spotlighted for everyone, from the room's metadata\n * (server-set, delivered on join). A local pin outranks it on this screen only.\n */\n readonly spotlight: ParticipantIdentity | null;\n /** The last thing a host did to THIS participant, in words. Dismissible. */\n readonly moderationNotice: ModerationNotice | null;\n /**\n * The server's answer to the last host action THIS participant took (\"Muted 3\n * people\", or the refusal). One place, so whichever surface acted — a tile's\n * menu, the People panel, More options — the sentence survives the menu closing.\n */\n readonly actionNotice: { readonly text: string; readonly failed: boolean; readonly at: number } | null;\n readonly effects: MediaEffects;\n /**\n * Captions AND durable rows, reconciled into one list (D16). A record\n * replaces the caption it supersedes; a caption never overwrites a record.\n */\n readonly transcript: readonly TranscriptSegment[];\n readonly notes: readonly MeetingNote[];\n /**\n * 🚨 IDENTITY → THE BEST NAME ANYTHING HAS EVER KNOWN (MRI-A16). Learned from\n * every source that has one — the roster, a durable segment, a durable\n * attendance row, a chat message — and never unlearned, so a caption that\n * lands after somebody leaves still says who spoke. It exists because the\n * host and the guest rendered DIFFERENT names for the same speaker in the\n * same second, one of them a raw LiveKit token (MRI-C8). See `core/names.ts`.\n */\n readonly names: NameBook;\n /**\n * The wrap-up pass ANNOUNCED itself (MRI-A12). `null` means it has not been\n * announced in this room — which is not the same as \"no summary exists\", and\n * no surface may render it as such.\n */\n readonly wrapUp: WrapUpAnnouncement | null;\n /**\n * The server's last refusal to dispatch the note-taker, in ITS words (D7).\n * Rendered verbatim; never replaced by a spinner or a house sentence.\n */\n readonly noteTakerRefusal: NoteTakerRefusal | null;\n /**\n * What the LOCAL participant is actually publishing, and why not when it is\n * not. Attendance never depends on it (see `attendance.ts`): a refused\n * microphone is a state with a remedy, not a failed join.\n */\n readonly media: LocalMediaState;\n /** The last failure, with its remedy. Never null-and-hoping. */\n readonly failure: { readonly message: string; readonly remedy: string } | null;\n}\n\nconst EMPTY: MeetSnapshot = {\n phase: \"idle\",\n meeting: null,\n localIdentity: null,\n grants: NO_GRANTS,\n participants: [],\n activeSpeakers: [],\n pinned: null,\n layout: \"grid\",\n lobby: [],\n locked: false,\n recording: \"idle\",\n recordingStartedBy: null,\n recordingSource: \"local\",\n recordingId: null,\n chat: [],\n chatLoaded: false,\n chatHistoryError: null,\n reactions: [],\n spotlight: null,\n moderationNotice: null,\n actionNotice: null,\n effects: DEFAULT_EFFECTS,\n transcript: [],\n notes: [],\n names: {},\n wrapUp: null,\n noteTakerRefusal: null,\n media: IDLE_MEDIA,\n failure: null,\n};\n\n/**\n * 🚨 THE ONE ANSWER TO \"WHAT ROLE DOES THIS CLIENT'S USER HOLD\" (MRI-A11).\n *\n * Two SERVER-minted carriers, one decision: the `/meet/token` response (in the\n * store from the moment the token lands, before any roster exists) and the\n * local participant's roster entry (whose role comes from the\n * `matrx.participant.role` LiveKit attribute). The stronger wins. Every host\n * power in this package — the UI that renders it AND the code that performs it\n * — asks THIS function, so a control can never render from one source and then\n * be refused by another. That split is exactly how a \"host control\" becomes a\n * button that throws.\n */\nexport function effectiveRole(snapshot: MeetSnapshot): ParticipantRole {\n const me = snapshot.participants.find(\n (participant) => participant.identity === snapshot.localIdentity,\n );\n const fromRoster = me?.role ?? \"participant\";\n const fromToken = snapshot.grants.role;\n return ROLE_RANK[fromRoster] >= ROLE_RANK[fromToken] ? fromRoster : fromToken;\n}\n\n/** Reactions live this long. A dropped end event cannot outlive it. */\nexport const REACTION_TTL_MS = 5_000;\n/** In-room chat is EPHEMERAL by design (R3) — this is the visible backlog. */\nconst CHAT_LIMIT = 200;\n\nexport interface MeetStore {\n snapshot(): MeetSnapshot;\n subscribe(listener: () => void): () => void;\n patch(next: Partial<MeetSnapshot>): void;\n setParticipants(participants: readonly MeetParticipant[]): void;\n setSpeaking(identities: readonly ParticipantIdentity[]): void;\n setQuality(identity: ParticipantIdentity, quality: ConnectionQuality): void;\n /**\n * Raise or lower a hand. `at` is WHEN it went up, which is the hand queue's\n * order — first raised, first called on, the way Meet orders it.\n */\n setHand(identity: ParticipantIdentity, raised: boolean, at?: number): void;\n addChat(message: RoomChatMessage): void;\n /** The saved chat, read once per join. Merged with anything that arrived live. */\n loadChat(messages: readonly RoomChatMessage[]): void;\n /** Replace a pending message (by id) with what the server saved, or mark it failed. */\n settleChat(localId: string, next: RoomChatMessage | { failed: string }): void;\n addReaction(reaction: RoomReaction): void;\n /** Drops reactions past their TTL. Called by the UI's animation frame. */\n expireReactions(now: number): void;\n /**\n * The recording reached a state, and WHO says so. `\"local\"` is this browser's\n * optimistic `starting`/`stopping`; `\"room\"` is the server's packet on the\n * media plane; `\"record\"` is the durable row. Precedence is D16's: the\n * database's word stands until the database changes it.\n */\n setRecording(\n state: RecordingState,\n by: UserId | null,\n source: RecordingSource,\n recordingId?: string | null,\n ): void;\n upsertLobby(entry: LobbyEntry): void;\n setAdmission(identity: ParticipantIdentity, state: AdmissionState, by: UserId | null): void;\n /**\n * Teach the name book. Every source that knows a name calls this, and only\n * a REAL name is learned — an identity handed back as its own name is not one.\n */\n learn(entries: readonly { identity: ParticipantIdentity; displayName?: string | null }[]): void;\n /** A live caption from the media plane. A HINT (D16). */\n ingestCaption(segment: TranscriptSegment): void;\n /** A durable `meet_transcript_segments` row. THE TRANSCRIPT (D16). */\n ingestRecord(segment: TranscriptSegment): void;\n /** Durable notes are re-written in place — a re-run rewrites the same ids. */\n upsertNote(note: MeetingNote): void;\n /** The wrap-up pass finished. Announced on the media plane only (MRI-A12). */\n announceWrapUp(announcement: WrapUpAnnouncement): void;\n /** Record what a local track ACTUALLY did — published, or refused and why. */\n setLocalTrack(kind: \"microphone\" | \"camera\", state: LocalTrackState): void;\n reset(): void;\n}\n\nexport function createMeetStore(initial: Partial<MeetSnapshot> = {}): MeetStore {\n let state: MeetSnapshot = { ...EMPTY, ...initial };\n const listeners = new Set<() => void>();\n\n function commit(next: MeetSnapshot): void {\n if (next === state) return;\n state = next;\n for (const listener of listeners) listener();\n }\n\n return {\n snapshot: () => state,\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n patch(next) {\n commit({ ...state, ...next });\n },\n setParticipants(participants) {\n // The roster TEACHES the book first — a participant whose token carried a\n // real name is where most names come from — and every roster entry is then\n // RESOLVED back through it, so a participant the roster cannot name still\n // gets the best name a durable row or a caption ever taught (MRI-A18).\n const names = learnNames(state.names, participants);\n // Hand-raise state lives on OUR side of the wire (it rides the data\n // plane, not the media plane), so it is carried across a roster replace\n // rather than reset — otherwise every mute event lowers every hand.\n const hands = new Map(state.participants.map((p) => [p.identity, p.handRaised]));\n const handTimes = new Map(state.participants.map((p) => [p.identity, p.handRaisedAt ?? null]));\n const quality = new Map(state.participants.map((p) => [p.identity, p.quality]));\n commit({\n ...state,\n names,\n participants: participants.map((participant) => ({\n ...participant,\n // 🚨 THE ONE ROSTER RESOLUTION. Every surface that renders a person —\n // the tile, the People row, the header summary, every Pin/Mute label —\n // reads `participant.displayName`, so this is the single place a raw\n // identity could reach a screen, and it is the place that asks the\n // name book. `roster-names.test.ts` fails if a token ever gets past it.\n displayName: displayNameFor(names, participant.identity, participant.displayName),\n handRaised: hands.get(participant.identity) ?? participant.handRaised,\n handRaisedAt: handTimes.get(participant.identity) ?? participant.handRaisedAt ?? null,\n quality:\n participant.quality === \"unknown\"\n ? quality.get(participant.identity) ?? \"unknown\"\n : participant.quality,\n })),\n });\n },\n setSpeaking(identities) {\n const speaking = new Set(identities);\n commit({\n ...state,\n activeSpeakers: identities,\n participants: state.participants.map((participant) =>\n participant.speaking === speaking.has(participant.identity)\n ? participant\n : { ...participant, speaking: speaking.has(participant.identity) },\n ),\n });\n },\n setQuality(identity, quality) {\n commit({\n ...state,\n participants: state.participants.map((participant) =>\n participant.identity === identity ? { ...participant, quality } : participant,\n ),\n });\n },\n setHand(identity, raised, at) {\n commit({\n ...state,\n participants: state.participants.map((participant) =>\n participant.identity === identity\n ? {\n ...participant,\n handRaised: raised,\n // A hand that is ALREADY up keeps its place in the queue when\n // it is re-announced (to a late joiner): the first time wins.\n handRaisedAt: raised\n ? participant.handRaised && participant.handRaisedAt != null\n ? participant.handRaisedAt\n : at ?? Date.now()\n : null,\n }\n : participant,\n ),\n });\n },\n addChat(message) {\n if (state.chat.some((existing) => existing.id === message.id)) return;\n const chat = [...state.chat, message];\n // A chat message carries its sender's name — another source, same book.\n const names = learnName(state.names, message.identity, message.displayName);\n commit({ ...state, chat: chat.slice(-CHAT_LIMIT), names });\n },\n loadChat(messages) {\n const known = new Set(state.chat.map((message) => message.id));\n const merged = [...messages.filter((message) => !known.has(message.id)), ...state.chat].sort(\n (a, b) => (a.at < b.at ? -1 : a.at > b.at ? 1 : 0),\n );\n const names = learnNames(\n state.names,\n messages.map((message) => ({ identity: message.identity, displayName: message.displayName })),\n );\n commit({ ...state, chat: merged.slice(-CHAT_LIMIT), chatLoaded: true, chatHistoryError: null, names });\n },\n settleChat(localId, next) {\n const index = state.chat.findIndex((message) => message.id === localId);\n if (index === -1) return;\n const current = state.chat[index] as RoomChatMessage;\n let replacement: RoomChatMessage;\n if (\"failed\" in next && typeof next.failed === \"string\" && !(\"id\" in next)) {\n replacement = { ...current, failed: next.failed };\n } else {\n replacement = next as RoomChatMessage;\n }\n // The saved copy may ALREADY be here (the room packet beat the response):\n // then the pending one simply goes.\n const duplicate =\n replacement.id !== localId && state.chat.some((message) => message.id === replacement.id);\n const chat = duplicate\n ? state.chat.filter((message) => message.id !== localId)\n : state.chat.map((message, position) => (position === index ? replacement : message));\n commit({ ...state, chat });\n },\n addReaction(reaction) {\n commit({ ...state, reactions: [...state.reactions, reaction] });\n },\n expireReactions(now) {\n const live = state.reactions.filter((reaction) => now - reaction.at < REACTION_TTL_MS);\n if (live.length === state.reactions.length) return;\n commit({ ...state, reactions: live });\n },\n setRecording(next, by, source, recordingId = null) {\n // 🚨 THE DATABASE WINS (D16). A member receives every transition TWICE —\n // the `meet_recordings` row over Postgres Changes and a\n // `matrx.meet.recording` packet in the room — and whichever is slower\n // must not be able to drag the indicator backwards.\n //\n // The rule is about ONE recording, not about the meeting: a meeting can\n // be recorded again, and the second recording's first word is not a\n // contradiction of the first one's ending. So the durable state stands\n // against anything that is about the SAME recording, and against a\n // sourceless update while a recording is still in flight.\n // `record` always wins. The other two are refused when they would\n // contradict the durable word rather than continue past it:\n //\n // * `local` is this browser acting NOW — a host pressing Start again on a\n // meeting whose last recording is over. It is refused only while a\n // recording is genuinely in flight, where a stale optimistic patch\n // could drag a live indicator backwards.\n // * `room` carries the recording's id, so a LATE packet about the\n // recording that just finished is told apart from the FIRST packet of\n // the next one. Same recording: refused. Different recording: refused\n // only while the durable one is still in flight.\n if (state.recordingSource === \"record\" && source !== \"record\") {\n const aboutTheSameRecording =\n source === \"room\" &&\n (recordingId === null ||\n state.recordingId === null ||\n recordingId === state.recordingId);\n if (aboutTheSameRecording || isRecordingInFlight(state.recording)) return;\n }\n if (\n state.recording === next &&\n state.recordingStartedBy === by &&\n state.recordingSource === source &&\n state.recordingId === (recordingId ?? state.recordingId)\n ) {\n // Identity-stable: an unchanged state must not wake every subscriber.\n return;\n }\n commit({\n ...state,\n recording: next,\n recordingStartedBy: by,\n recordingSource: source,\n recordingId: recordingId ?? state.recordingId,\n });\n },\n upsertLobby(entry) {\n const index = state.lobby.findIndex((existing) => existing.identity === entry.identity);\n const lobby =\n index === -1\n ? [...state.lobby, entry]\n : state.lobby.map((existing, position) => (position === index ? entry : existing));\n commit({ ...state, lobby });\n },\n setAdmission(identity, admissionState, by) {\n commit({\n ...state,\n lobby: state.lobby.map((entry) =>\n entry.identity === identity\n ? {\n ...entry,\n state: admissionState,\n decidedAt: new Date().toISOString(),\n decidedBy: by,\n }\n : entry,\n ),\n });\n },\n learn(entries) {\n const names = learnNames(state.names, entries);\n // Identity-stable: learning nothing must not wake every subscriber, and\n // this is called on every roster event and every durable row.\n if (names === state.names) return;\n commit({ ...state, names });\n },\n ingestCaption(segment) {\n // A caption's roster lookup is a source of names like any other.\n const names = learnName(state.names, segment.identity, segment.speaker);\n const transcript = mergeCaption(state.transcript, segment);\n if (transcript === state.transcript && names === state.names) return;\n commit({ ...state, transcript, names });\n },\n ingestRecord(segment) {\n // 🚨 THE DURABLE ROW'S `speaker` IS THE BEST NAME THERE IS: the note-taker\n // wrote it from `meet_participants`, which is where \"Ada Lovelace\" lived\n // while the guest's screen was printing `guest:c8-spk-1`.\n const names = learnName(state.names, segment.identity, segment.speaker);\n const transcript = mergeRecord(state.transcript, segment);\n if (transcript === state.transcript && names === state.names) return;\n commit({ ...state, transcript, names });\n },\n upsertNote(note) {\n const index = state.notes.findIndex((existing) => existing.id === note.id);\n if (index === -1) {\n commit({ ...state, notes: [...state.notes, note] });\n return;\n }\n const existing = state.notes[index];\n // Identity-stable: an unchanged note must not wake `useSyncExternalStore`.\n // 🚨 `source` is part of \"unchanged\" and that is load-bearing, not\n // cosmetic: when the room copy and the database copy carry the same words,\n // dropping the second arrival would leave the note marked `\"room\"` forever\n // — and the precedence rule below would then let a LATER stale packet\n // overwrite a row the database had already confirmed.\n if (\n existing !== undefined &&\n existing.text === note.text &&\n existing.kind === note.kind &&\n existing.supersededBy === note.supersededBy &&\n existing.source === note.source\n ) {\n return;\n }\n // 🚨 THE DATABASE WINS (D16, MRI-A12). The identical row arrives on two\n // transports — a `meet_notes` row over Postgres Changes and a\n // `matrx.meet.note` packet on the media plane — and whichever is slower\n // must not be able to undo the other. A `\"room\"` copy never overwrites a\n // `\"record\"` one; a `\"record\"` copy always overwrites a `\"room\"` one.\n // Without this, a re-run that rewrote a note could flip a member's screen\n // back to the superseded wording purely on arrival order.\n if (existing !== undefined && existing.source === \"record\" && note.source === \"room\") {\n return;\n }\n commit({\n ...state,\n notes: state.notes.map((entry, position) => (position === index ? note : entry)),\n });\n },\n announceWrapUp(announcement) {\n const current = state.wrapUp;\n if (current !== null && current.at === announcement.at) return;\n commit({ ...state, wrapUp: announcement });\n },\n setLocalTrack(kind, next) {\n const current = state.media[kind];\n // Identity-stable: an unchanged track must not wake `useSyncExternalStore`.\n if (\n current.enabled === next.enabled &&\n current.unavailable?.code === next.unavailable?.code &&\n current.unavailable?.message === next.unavailable?.message\n ) {\n return;\n }\n commit({ ...state, media: { ...state.media, [kind]: next } });\n },\n reset() {\n // A person's own media choices outlive a room: they are theirs, per browser.\n commit({ ...EMPTY, effects: state.effects });\n },\n };\n}\n","/**\n * MEETINGS — the lobby, the host powers, and the durable link.\n *\n * A meeting is a room plus scheduling, lobby and host metadata (D3). Everything\n * here is about the moments OUTSIDE the media session, which is exactly why it\n * cannot ride LiveKit's data plane: a guest waiting in the lobby is not in the\n * LiveKit room yet, by construction. The lobby therefore lives on the meet-room\n * realtime channel.\n *\n * 🚨 THE THREE THINGS THAT MAKE GUEST JOIN SAFE (D6)\n *\n * 1. **The link is an identity, not a session.** A durable slug resolves before,\n * during, and after the scheduled time, and a recurring meeting keeps ONE\n * link. Nothing here mints a per-occurrence URL.\n * 2. **A guest's capability is the TOKEN, and nothing else.** They are scoped to\n * exactly one room. There is no guest row this client writes that could grant\n * anything, and no client-side \"is this person allowed\" branch.\n * 3. **Admission is a SERVER decision, recorded.** `admit` is an RPC; the\n * broadcast that tells the knocker is a NOTIFICATION of that decision, never\n * the decision itself. Two hosts clicking admit is the ordinary case, and the\n * RPC is what makes it idempotent.\n *\n * Host powers are checked against the role the SERVER minted into the token\n * (see `room.ts`), and the UI hides what an actor cannot do rather than\n * rendering a dead button (no dead ends).\n */\n\nimport type { ChannelHandle, RealtimeManager } from \"@ai-matrx/realtime\";\nimport { MEET_EVENTS, meetingTopic, roomTopic } from \"./channels\";\nimport type { MeetApi } from \"./api\";\nimport { MeetError } from \"./errors\";\nimport { readServerRefusal } from \"./ai\";\nimport type { MeetRepository } from \"./repository\";\nimport { effectiveRole, type MeetStore } from \"./store\";\nimport { MEET_ROUTES } from \"./tokens\";\nimport {\n asParticipantIdentity,\n isHostRole,\n isGuest,\n ROLE_RANK,\n type LobbyEntry,\n type MeetIdentity,\n type MeetParticipant,\n type MeetingAttendee,\n type MeetingId,\n type MeetingRecord,\n type ParticipantIdentity,\n type ParticipantRole,\n type RecordingState,\n type RoomName,\n type UserId,\n} from \"./types\";\n\nexport interface MeetingSessionOptions {\n manager: RealtimeManager;\n repository: MeetRepository;\n store: MeetStore;\n identity: MeetIdentity;\n /**\n * The ONE org-aware aidream client (MRI-A16) — `endForEveryone` is a SERVER\n * decision (MRI-A6), and every request it makes carries the organization.\n */\n api: MeetApi;\n onDiagnostic?: ((event: { level: \"info\" | \"warn\" | \"error\"; message: string; remedy?: string }) => void) | undefined;\n /**\n * 🚨 THE HOST ADMITTED *US*. Called exactly once per admission verdict that\n * names this participant, and only for `admitted`.\n *\n * Admission is not a UI state change: a lobby token is minted with\n * `canPublish: false` and `canSubscribe: false`, so the waiting room can only\n * become a room by minting a NEW token. Before this existed the waiting room\n * said \"you will join automatically once you are admitted\" and then waited\n * forever — a sentence on screen that was not true. The provider wires this\n * to `engine.rejoin()`.\n */\n onAdmitted?: (() => void) | undefined;\n /**\n * 🚨 THE HOST DENIED *US*. Called once per denial verdict that names this\n * knocker. Without it the waiting room kept promising \"you will join\n * automatically\" to a person the host had already turned away (production\n * 2026-09-27). The provider wires it to `engine.rejoin()`: the server then\n * refuses the mint with its own sentence (\"The host did not admit you…\"),\n * so the words on screen are the server's decision, never the client's guess.\n */\n onDenied?: (() => void) | undefined;\n}\n\nexport interface MeetingSession {\n /** Subscribe to the room's out-of-band plane. Hosts see knocks; guests see verdicts. */\n watch(roomName: RoomName): void;\n /**\n * Subscribe to the MEETING RECORD's durable feed — transcript segments, notes,\n * and the meeting row itself (which is where the note-taker's state lives).\n * Reconnecting IS re-reading: the backfill door re-reads all three, because\n * realtime has no replay and a socket blip would otherwise leave a transcript\n * permanently missing the minute nobody noticed.\n */\n watchMeeting(meetingId: MeetingId): void;\n /** A guest (or a late arrival at a locked room) announces themselves. */\n knock(roomName: RoomName): void;\n admit(entry: LobbyEntry, admitted: boolean): Promise<void>;\n admitAll(): Promise<void>;\n setLock(locked: boolean): Promise<MeetingRecord>;\n /** End it for everyone, through the server (MRI-A6). */\n endForEveryone(): Promise<EndMeetingResult>;\n dispose(): void;\n}\n\n/** Can `actor` moderate `target`? A host outranks a co-host outranks everyone. */\nexport function canModerateParticipant(\n actor: MeetParticipant | undefined,\n target: MeetParticipant | undefined,\n): boolean {\n if (actor === undefined || target === undefined) return false;\n if (actor.role === \"participant\") return false;\n if (actor.identity === target.identity) return false;\n // A co-host cannot remove the host. Without this rank check, \"host controls\"\n // is a mutual-eviction button.\n return ROLE_RANK[actor.role] > ROLE_RANK[target.role];\n}\n\nexport function roleOf(\n participants: readonly MeetParticipant[],\n identity: ParticipantIdentity | null,\n): ParticipantRole {\n if (identity === null) return \"participant\";\n return participants.find((p) => p.identity === identity)?.role ?? \"participant\";\n}\n\n/**\n * What ending a meeting produced. `served: false` is the honest answer from a\n * server that has not landed `POST /v1/meet/end` yet (MRI-A6) — the control is\n * real, the refusal is a sentence, and nothing pretends the meeting ended.\n */\nexport interface EndMeetingResult {\n readonly endedAt: string | null;\n readonly served: boolean;\n}\n\n/** The sentence a server without MRI-A6 earns. Pinned so every surface says it. */\nexport const END_MEETING_NOT_SERVED =\n \"Ending a meeting is not available on this server yet\";\n\n/**\n * One durable `meet_participants` row as a lobby entry, or `null` when it is\n * not one. A row that has been decided is not a knocker; the panel shows people\n * who are WAITING, and `store.upsertLobby` keyed by identity is what lets the\n * table and the broadcast be two copies of one person rather than two rows.\n */\nfunction lobbyEntryFrom(attendee: MeetingAttendee): LobbyEntry | null {\n if (attendee.admissionState !== \"knocking\") return null;\n return {\n identity: attendee.identity,\n displayName: attendee.displayName,\n avatarUrl: attendee.avatarUrl,\n userId: attendee.userId,\n state: \"knocking\",\n knockedAt: attendee.joinedAt ?? new Date().toISOString(),\n decidedAt: null,\n decidedBy: null,\n };\n}\n\nexport function createMeetingSession(options: MeetingSessionOptions): MeetingSession {\n const { manager, repository, store, identity } = options;\n let channel: ChannelHandle | null = null;\n let meetingChannel: ChannelHandle | null = null;\n\n /**\n * The meeting row, for anyone who may be in it. A member or a person the\n * meeting was shared with reads it under RLS; a signed-in person from ANOTHER\n * organization who followed the link cannot, and gets the same row through\n * the link door (`meet_meeting_by_slug`) a guest uses — the server lets them\n * in by the link, so the screen must not fail them for holding it.\n */\n async function readMeeting(meetingId: MeetingId): Promise<MeetingRecord> {\n try {\n return await repository.meeting(meetingId);\n } catch (error) {\n const slug = store.snapshot().meeting?.slug;\n if (slug === undefined) throw error;\n return repository.meetingBySlug(slug);\n }\n }\n\n function requireHostUser(operation: string): UserId {\n // THE SAME PREDICATE THE UI RENDERS FROM (MRI-A11). Reading only the roster\n // here — while the control renders from the token grant — is how a host\n // control becomes a button that throws the moment it is used.\n if (identity.userId === null || !isHostRole(effectiveRole(store.snapshot()))) {\n throw new MeetError(\n \"forbidden\",\n `${operation}: this participant is not a host`,\n \"Host powers come from the server-minted token metadata and are enforced by the RPC. \" +\n \"Hide the control rather than rendering a button that will be refused.\",\n );\n }\n return identity.userId;\n }\n\n /**\n * ONE definition of \"who am I in the lobby\", used to knock AND to hear back.\n * It MUST equal the identity the token route writes on the lobby row\n * (aidream `participant_identity`: `user:<uuid>` or `guest:<device>`). A bare\n * uuid here gave a signed-in outsider two lobby entries on the host's panel;\n * admitting the bare one decided a row nobody held and they waited forever.\n */\n function knockIdentity(): ParticipantIdentity {\n return asParticipantIdentity(\n identity.userId !== null ? `user:${identity.userId}` : `guest:${identity.deviceId}`,\n );\n }\n\n function requireMeeting(operation: string): MeetingRecord {\n const meeting = store.snapshot().meeting;\n if (meeting === null) {\n throw new MeetError(\n \"misconfigured\",\n `${operation}: no meeting is loaded`,\n \"Ad-hoc call rooms have no meeting record and therefore no lobby or lock. Use \" +\n \"joinMeeting()/scheduleMeeting() when you need those powers.\",\n );\n }\n return meeting;\n }\n\n return {\n watch(roomName) {\n channel?.close();\n channel = manager.open({\n topic: roomTopic(roomName),\n broadcast: [\n {\n event: MEET_EVENTS.knock,\n onMessage: (message) => {\n store.upsertLobby(message.data as LobbyEntry);\n },\n },\n {\n event: MEET_EVENTS.admission,\n onMessage: (message) => {\n const verdict = message.data as {\n identity: string;\n admitted: boolean;\n by: string | null;\n };\n const decided = asParticipantIdentity(verdict.identity);\n store.setAdmission(\n decided,\n verdict.admitted ? \"admitted\" : \"denied\",\n verdict.by === null ? null : (verdict.by as UserId),\n );\n // THE VERDICT IS ABOUT US, AND IT IS YES. The identity compared\n // here is the KNOCK identity (see `knock()` below), which is what\n // the host's admit RPC and this broadcast both carry — not the\n // LiveKit participant identity, which a lobby joiner does not\n // have yet because they are not in the room.\n if (decided === knockIdentity()) {\n if (verdict.admitted) options.onAdmitted?.();\n else options.onDenied?.();\n }\n },\n },\n {\n event: MEET_EVENTS.lock,\n onMessage: (message) => {\n const { locked } = message.data as { locked: boolean };\n const meeting = store.snapshot().meeting;\n store.patch({\n locked,\n ...(meeting !== null ? { meeting: { ...meeting, locked } } : {}),\n });\n },\n },\n {\n event: MEET_EVENTS.recording,\n onMessage: (message) => {\n const payload = message.data as { state: string; by: string | null };\n // EVERY participant renders the indicator, guests included (R5).\n // This is why recording state is broadcast rather than derived\n // from a host-only read. It is `\"room\"`, so the durable row\n // outranks it (D16) — see `store.setRecording`.\n store.setRecording(\n payload.state as RecordingState,\n payload.by === null ? null : (payload.by as UserId),\n \"room\",\n );\n },\n },\n ],\n // THE BACKFILL DOOR. A host whose socket blipped must not miss a knock:\n // re-reading the meeting restores lock/recording truth, and knockers\n // re-announce on their own timer.\n onBackfill: async () => {\n const meeting = store.snapshot().meeting;\n if (meeting === null) return;\n const fresh = isGuest(identity)\n ? await repository.meetingBySlug(meeting.slug)\n : await readMeeting(meeting.id);\n store.patch({ meeting: fresh, locked: fresh.locked });\n },\n });\n },\n\n watchMeeting(meetingId) {\n meetingChannel?.close();\n meetingChannel = null;\n if (isGuest(identity)) {\n options.onDiagnostic?.({\n level: \"info\",\n message: \"Guest notes and captions arrive through the live meeting room; saved history is not available without a session.\",\n remedy: \"Sign in with access to this meeting to reload saved notes and transcript history.\",\n });\n return;\n }\n meetingChannel = manager.open({\n topic: meetingTopic(meetingId),\n postgresChanges: [\n {\n event: \"*\",\n schema: repository.schema,\n table: repository.tables.transcripts,\n filter: `meeting_id=eq.${meetingId}`,\n rowId: (row) => (typeof row[\"id\"] === \"string\" ? row[\"id\"] : undefined),\n onChange: ({ row }) => {\n // D16: THE ROW IS THE TRANSCRIPT. It replaces the caption that\n // showed the same words a moment earlier.\n if (row !== null) store.ingestRecord(repository.projectSegment(row));\n },\n },\n {\n event: \"*\",\n schema: repository.schema,\n table: repository.tables.notes,\n filter: `meeting_id=eq.${meetingId}`,\n rowId: (row) => (typeof row[\"id\"] === \"string\" ? row[\"id\"] : undefined),\n onChange: ({ row }) => {\n // Upsert, not append: a re-run of the wrap-up rewrites the SAME\n // row ids by design, and appending would show every note twice.\n if (row !== null) store.upsertNote(repository.projectNote(row));\n },\n },\n {\n // 🚨 THE LOBBY IS A TABLE, NOT ONLY A CHANNEL (MRI-A16). A guest\n // knocks by writing `admission_state='knocking'` AND broadcasting;\n // through 0.4.7 the host's People panel rendered only the broadcast,\n // so a knocker whose packet landed before this browser opened the\n // channel — a host who joined second, reloaded, or slept a laptop —\n // was INVISIBLE while the guest sat in the waiting room forever. A\n // host can read this table; a guest cannot, and gets no lobby list\n // at all, which is correct.\n event: \"*\",\n schema: repository.schema,\n table: repository.tables.participants,\n filter: `meeting_id=eq.${meetingId}`,\n rowId: (row) => (typeof row[\"id\"] === \"string\" ? row[\"id\"] : undefined),\n onChange: ({ row }) => {\n if (row === null) return;\n const attendee = repository.projectAttendee(row);\n store.learn([attendee]);\n const entry = lobbyEntryFrom(attendee);\n if (entry !== null) {\n store.upsertLobby(entry);\n return;\n }\n // 🚨 A DECIDED ROW MUST CLEAR THE DOOR. Admitting a guest from\n // another tab writes `admitted` here, and simply ignoring the row\n // would leave this host's panel offering to admit somebody who is\n // already in the meeting — a ghost knocker who can never be\n // dismissed. The durable row is the verdict, wherever it was made.\n store.setAdmission(attendee.identity, attendee.admissionState, null);\n },\n },\n {\n event: \"*\",\n schema: repository.schema,\n table: repository.tables.recordings,\n filter: `meeting_id=eq.${meetingId}`,\n rowId: (row) => (typeof row[\"id\"] === \"string\" ? row[\"id\"] : undefined),\n onChange: ({ row }) => {\n // 🚨 THE INDICATOR RENDERS THE DURABLE STATE, not this browser's\n // hope. Through 0.4.7 nothing subscribed here, so the only\n // transitions the store ever saw were the optimistic `starting`\n // and `stopping` THIS client patched — and the indicator sat on\n // \"Starting recording…\" for a whole meeting while a healthy\n // egress ran, then \"Stopping recording…\" forever (MRI-C8).\n if (row === null) return;\n const recording = repository.projectRecording(row);\n store.setRecording(recording.state, recording.startedBy, \"record\", recording.id);\n },\n },\n {\n event: \"*\",\n schema: repository.schema,\n table: repository.tables.meetings,\n filter: `id=eq.${meetingId}`,\n rowId: (row) => (typeof row[\"id\"] === \"string\" ? row[\"id\"] : undefined),\n onChange: ({ row }) => {\n // The note-taker's state lives on this row's metadata (D9/MRI-A2),\n // so this subscription is what keeps each server-recorded state\n // current on screen without a reload.\n if (row === null) return;\n const meeting = repository.projectMeeting(row);\n store.patch({ meeting, locked: meeting.locked });\n },\n },\n ],\n // THE BACKFILL DOOR. Realtime has no replay: everything that happened\n // while the socket was down is gone. Re-reading all three is what keeps\n // a recovered surface from looking healthy and being wrong.\n onBackfill: async () => {\n const [meeting, transcript, notes, recordings, attendees] = await Promise.all([\n readMeeting(meetingId),\n repository.transcript(meetingId),\n repository.notes(meetingId),\n repository.recordings(meetingId),\n repository.attendees(meetingId),\n ]);\n store.patch({ meeting, locked: meeting.locked });\n for (const segment of transcript) store.ingestRecord(segment);\n for (const note of notes) store.upsertNote(note);\n // A socket blip must not leave the indicator saying something the\n // database stopped agreeing with ten minutes ago. `recordings` is\n // newest first.\n const latest = recordings[0];\n if (latest !== undefined) {\n store.setRecording(latest.state, latest.startedBy, \"record\", latest.id);\n }\n // Everyone the durable rows know a name for, and every knocker still\n // waiting. A host who reloads must not lose a person at the door.\n store.learn(attendees);\n for (const attendee of attendees) {\n const entry = lobbyEntryFrom(attendee);\n if (entry !== null) {\n store.upsertLobby(entry);\n } else {\n // The same rule on the backfill door: a host who reloads must not\n // find people at the door who were admitted while they were gone.\n store.setAdmission(attendee.identity, attendee.admissionState, null);\n }\n }\n },\n });\n // The FIRST read is the same read: a surface that joins a meeting already\n // in progress must see what was already said.\n meetingChannel.requestBackfill(\"manual\");\n },\n\n knock(roomName) {\n const handle = channel ?? manager.open({ topic: roomTopic(roomName) });\n channel = handle;\n const entry: LobbyEntry = {\n identity: knockIdentity(),\n displayName: identity.displayName,\n avatarUrl: identity.avatarUrl,\n userId: identity.userId,\n state: \"knocking\",\n knockedAt: new Date().toISOString(),\n decidedAt: null,\n decidedBy: null,\n };\n store.upsertLobby(entry);\n handle.send(MEET_EVENTS.knock, entry);\n },\n\n async admit(entry, admitted) {\n const by = requireHostUser(\"meet.admit\");\n const meeting = requireMeeting(\"meet.admit\");\n // The RPC IS the decision. The broadcast below only tells the knocker,\n // who has no database read of their own — they are a guest.\n await repository.admit({\n meetingId: meeting.id,\n identity: entry.identity,\n admitted,\n byUserId: by,\n });\n // UPSERT, not patch-if-present. A host can decide on a knock this store\n // never saw (the knock arrived before this tab subscribed, or a second\n // host is deciding), and `setAdmission` on an unknown identity would do\n // nothing at all — a silent no-op behind a button that looked like it\n // worked.\n store.upsertLobby({\n ...entry,\n state: admitted ? \"admitted\" : \"denied\",\n decidedAt: new Date().toISOString(),\n decidedBy: by,\n });\n channel?.send(MEET_EVENTS.admission, {\n identity: entry.identity,\n admitted,\n by,\n });\n },\n\n async admitAll() {\n const knocking = store.snapshot().lobby.filter((entry) => entry.state === \"knocking\");\n for (const entry of knocking) {\n await this.admit(entry, true);\n }\n },\n\n async setLock(locked) {\n const by = requireHostUser(\"meet.setLock\");\n const meeting = requireMeeting(\"meet.setLock\");\n const updated = await repository.setLock(meeting.id, locked, by);\n store.patch({ meeting: updated, locked: updated.locked });\n channel?.send(MEET_EVENTS.lock, { locked: updated.locked });\n return updated;\n },\n\n /**\n * END IT FOR EVERYONE — a SERVER decision, not a row this client updates.\n *\n * 0.2.1 called the `meet_end_meeting` RPC directly, which ended the meeting\n * in the database while LiveKit kept the room open and the note-taker kept\n * writing into an ended meeting. `POST /v1/meet/end` re-checks the host,\n * closes the room, and triggers the wrap-up — one decision, one place\n * (MRI-A6).\n *\n * 🚨 A SERVER THAT HAS NOT LANDED THAT ROUTE ANSWERS 404, and that is\n * reported as a sentence, never as a dead control and never as a success.\n */\n async endForEveryone() {\n requireHostUser(\"meet.endForEveryone\");\n const meeting = requireMeeting(\"meet.endForEveryone\");\n const response = await options.api.request({\n path: MEET_ROUTES.meetingEnd,\n method: \"POST\",\n requireAuth: true,\n operation: \"meet.endForEveryone\",\n body: {\n meeting_id: meeting.id,\n organization_id: identity.organizationId,\n },\n });\n if (response.status === 404) {\n return { endedAt: null, served: false };\n }\n if (!response.ok) {\n let body: unknown = null;\n try {\n body = await response.json();\n } catch {\n body = null;\n }\n const refusal = readServerRefusal(body);\n throw new MeetError(\n response.status === 403 ? \"forbidden\" : \"transport\",\n refusal?.reason ?? `meet.endForEveryone: the server answered ${response.status}`,\n refusal?.remedy !== undefined && refusal.remedy.length > 0\n ? refusal.remedy\n : \"The meeting is still running. Only a host may end it, and the server \" +\n \"re-checks that — being a host on this screen is not the decision.\",\n );\n }\n let payload: unknown = null;\n try {\n payload = await response.json();\n } catch {\n payload = null;\n }\n const row =\n typeof payload === \"object\" && payload !== null\n ? (payload as Record<string, unknown>)\n : {};\n const endedAt =\n typeof row[\"ended_at\"] === \"string\" ? row[\"ended_at\"] : new Date().toISOString();\n const current = store.snapshot().meeting;\n if (current !== null) store.patch({ meeting: { ...current, endedAt } });\n return { endedAt, served: true };\n },\n\n dispose() {\n channel?.close();\n channel = null;\n meetingChannel?.close();\n meetingChannel = null;\n },\n };\n}\n\n/**\n * A durable public slug. Lowercase, hyphenated, and deliberately readable —\n * people read these aloud on phone calls. The alphabet excludes the four\n * characters that get misheard (0/O, 1/l).\n */\nconst SLUG_ALPHABET = \"abcdefghijkmnpqrstuvwxyz23456789\";\n\nexport function meetingSlug(random: () => number = Math.random): string {\n const group = (length: number): string =>\n Array.from({ length }, () => {\n const index = Math.floor(random() * SLUG_ALPHABET.length);\n return SLUG_ALPHABET[index] ?? \"a\";\n }).join(\"\");\n return `${group(3)}-${group(4)}-${group(3)}`;\n}\n\n/** The link a host copies. ONE shape, so every surface produces the same URL. */\nexport function meetingLink(baseUrl: string, slug: string): string {\n return `${baseUrl.replace(/\\/+$/, \"\")}/meet/${slug}`;\n}\n","/**\n * THE DATA CONTRACT — the ONE place a meet table or RPC name exists.\n *\n * 🚨 **STATE OF THE SCHEMA (read this before believing a green test).** The\n * `communication.meet_*` tables below are the canonical schema DESIGNED by this\n * package per R8; they are **not deployed to Matrx Main yet**. They were placed\n * by inspecting the live database on 2026-08-31: `communication` is the schema\n * that already holds `dm_*` (messaging) and `sms_*` (telephony), so meet takes\n * the `meet_*` prefix in the same schema rather than inventing a new one. Until\n * the migration lands, every read here fails LOUDLY with `not-found` and a\n * remedy naming this file — never silently, and never with a fabricated row.\n * The migration and the aidream server half are one deliverable; see FEATURE.md\n * § Deliberately NOT in this package.\n *\n * Four rules hold this file together — the same four that hold messaging's:\n *\n * 1. **Org is explicit on every write (R5).** Not defaulted by a trigger we\n * hope fires — passed, and refused in-package when absent.\n * 2. **Authorization is the database's job.** There is no permission branch in\n * this file. An RPC that says no is a `forbidden` MeetError, never a\n * client-side re-decision. Guest capability is scoped by the room TOKEN, not\n * by a row this client could write.\n * 3. **Writes go through SECURITY DEFINER RPCs; reads are RLS-backed table\n * reads** (C17's hybrid ruling). Every write here is an RPC, which is also\n * what keeps admission and settle-a-call ATOMIC — two hosts clicking \"admit\"\n * and a callee accepting on two devices are the ordinary case, not the edge.\n * 4. **Pagination is keyset, terminated by a unique column.** `(created_at,\n * id)` — never a timestamp alone, which duplicates or skips rows whenever\n * two share a millisecond.\n *\n * The Supabase client is accepted STRUCTURALLY, through the shape\n * `@ai-matrx/messaging` already owns. One definition of \"a Supabase client\" for\n * the whole communications family; this package adds no second copy.\n *\n * 🚨 AND THE PUBLIC BOUNDARY IS THE SHALLOW ONE (0.2.1). `RepositoryOptions`\n * and `<MeetProvider client>` take `MessagingSupabaseClient` — method names and\n * arity, results as `unknown` — never the rich `SupabaseLike`. Checking a\n * host's real `SupabaseClient<Database>` (built from generated types) against\n * the rich shape makes tsc chase PostgREST's schema machinery until it bails\n * with `TS2589: Type instantiation is excessively deep and possibly infinite`,\n * so the only way to pass the client a host ALREADY HAS was a cast — which is\n * what the first real consumer had to write (register MRI-D1). Messaging 0.9.0\n * learned this and wrote it down; this package did not apply the lesson until\n * now. The rich shape stays the INTERNAL contract, and we narrow to it ONCE,\n * here, in-package.\n */\n\nimport type { MessagingSupabaseClient, SupabaseLike } from \"@ai-matrx/messaging\";\nimport { invalidResponse, MeetError, normalizeMeetError } from \"./errors\";\nimport {\n asCallId,\n asMeetingId,\n asOrganizationId,\n asParticipantIdentity,\n asRoomName,\n asUserId,\n type CallId,\n type CallInvite,\n type CallMode,\n type CallState,\n type JsonObject,\n type MeetingId,\n type MeetingKind,\n type MeetingAttendee,\n type MeetingNote,\n type MeetingRecord,\n type ParticipantRole,\n type AdmissionState,\n type OrganizationId,\n type RecordingPolicy,\n type RecordingRecord,\n type RecordingRetention,\n type RecordingState,\n type RoomName,\n type TranscriptSegment,\n type UserId,\n type InviteeInput,\n type InviteeRole,\n type MeetingChanges,\n type MeetingInvitee,\n type MeetingOccurrence,\n type MeetingSettings,\n type OccurrenceOverride,\n type OccurrenceState,\n type RsvpAnswer,\n type RsvpInvitation,\n type RsvpState,\n type UpcomingOccurrence,\n} from \"./types\";\n\n/** The schema. Meet is never in `public`. */\nexport const MEET_SCHEMA = \"communication\";\n\nexport const TABLES = {\n meetings: \"meet_meetings\",\n participants: \"meet_participants\",\n invites: \"meet_call_invites\",\n recordings: \"meet_recordings\",\n transcripts: \"meet_transcript_segments\",\n notes: \"meet_notes\",\n /** Wave 1 (0.8): who a meeting was sent to, and what they answered. */\n invitees: \"meet_invitees\",\n /** Wave 1 (0.8): one occurrence of a series cancelled or moved. */\n occurrenceOverrides: \"meet_occurrence_overrides\",\n} as const;\n\nexport const RPCS = {\n /** Atomic: create the invite row and stamp its expiry in one statement. */\n createCallInvite: \"meet_create_call_invite\",\n /** Atomic settle. Refuses a transition out of a terminal state. */\n settleCallInvite: \"meet_settle_call_invite\",\n /** Every invite still ringing this user — the reconnect backfill door. */\n pendingCallInvites: \"meet_pending_call_invites\",\n /** Instant meeting, or the durable one behind a recurring link. */\n getOrCreateMeeting: \"meet_get_or_create_meeting\",\n /** Resolve a durable public link, before/during/after its scheduled time. */\n meetingBySlug: \"meet_meeting_by_slug\",\n admit: \"meet_admit_participant\",\n setLock: \"meet_set_lock\",\n endMeeting: \"meet_end_meeting\",\n recordConsent: \"meet_record_consent\",\n /*\n * ── MEET WAVE 1 — management (0.8). Every write is a SECURITY DEFINER door\n * authorized by the meeting's host or a real iam grant (editor to change,\n * admin = co-host to archive or name a co-host) — never an organization\n * match. After any of these writes, call `announceMeeting` so the server\n * sends invitations / updates / cancellations and re-queues reminders.\n */\n /** Schedule with every setting at create; unset settings come from the knobs. */\n scheduleMeeting: \"meet_schedule_meeting\",\n /** Edit / reschedule — a JSON patch with a version compare-and-swap. */\n updateMeeting: \"meet_update_meeting\",\n /** Cancel is a state (`cancelled_at`); the link keeps resolving. */\n cancelMeeting: \"meet_cancel_meeting\",\n /** Archive (soft delete) — the invitations and exceptions cascade. */\n archiveMeeting: \"meet_archive_meeting\",\n restoreMeeting: \"meet_restore_meeting\",\n /** Cancel, move or restore ONE occurrence of a series by its original start. */\n setOccurrence: \"meet_set_occurrence\",\n addInvitees: \"meet_add_invitees\",\n setInviteeRole: \"meet_set_invitee_role\",\n removeInvitee: \"meet_remove_invitee\",\n /** A signed-in invitee answers for themselves. */\n respond: \"meet_respond\",\n /** The emailed RSVP link (no account): read and answer. */\n invitationByToken: \"meet_invitation_by_token\",\n respondByToken: \"meet_respond_by_token\",\n /** One meeting's occurrences between two instants (INVOKER — the reader's RLS). */\n meetingOccurrences: \"meet_meeting_occurrences\",\n /** Every occurrence the reader can see between two instants — the Upcoming list. */\n occurrencesBetween: \"meet_occurrences_between\",\n /*\n * ── MEET WAVE 3 — after the meeting. Both INVOKER (the reader's RLS) and both\n * scoped to the reader's OWN meetings (host, invitee, attended) — RLS is the\n * ceiling, never the view.\n */\n /** The recordings library. */\n myRecordings: \"meet_my_recordings\",\n /** Titles, agendas, current notes and final transcript lines; snippets mark hits with ⟦ ⟧. */\n search: \"meet_search\",\n} as const;\n\n/**\n * THE RPCs THAT RETURN NOTHING, verified against the live database\n * (`pg_get_function_result`, 2026-09-08). They go through `guardVoid`; every\n * other RPC returns a row and goes through `guard`. Wiring a void RPC to\n * `guard` makes a SUCCESSFUL write look like a failure — see `guardVoid`.\n */\nexport const VOID_RPCS: readonly string[] = [RPCS.admit, RPCS.recordConsent];\n\nconst MEETING_COLUMNS =\n \"id,organization_id,room_name,slug,title,kind,host_user_id,scheduled_for,\" +\n \"scheduled_duration_minutes,started_at,ended_at,locked,lobby_enabled,\" +\n \"recording_policy,ai_enabled,metadata,\" +\n // Wave 1 (0.8).\n \"time_zone,agenda,recurrence_rule,join_before_host,cancelled_at,cancellation_reason,\" +\n \"deleted_at,calendar_sequence,version\";\n\nconst INVITEE_COLUMNS =\n \"id,meeting_id,invitee_user_id,email,display_name,role,rsvp_state,responded_at,\" +\n \"rsvp_note,last_sent_sequence,last_sent_at\";\n\n/**\n * The invite row's columns. Not used by a `select` today — every invite read\n * and write goes through an RPC (C17's hybrid: writes are SECURITY DEFINER,\n * and a settle must be atomic) — but it is part of the contract S2's migration\n * has to satisfy, and it is what `projectInvite` reads out of an RPC's return\n * row. Keep it in step with that function.\n */\nconst INVITE_COLUMNS =\n \"id,organization_id,room_name,mode,caller_user_id,caller_name,caller_avatar_url,\" +\n \"callee_ids,conversation_id,created_at,expires_at,state,decline_message\";\n\nconst RECORDING_COLUMNS =\n \"id,meeting_id,state,started_at,ended_at,started_by,file_id,failure_reason\";\n\n/**\n * THE TRANSCRIPT'S COLUMNS. `is_final` — not `final` — is the live column name,\n * and only final rows are ever written (D6: an interim is a caption and a\n * caption is never persisted).\n */\nconst SEGMENT_COLUMNS = \"id,meeting_id,identity,speaker,text,started_at,is_final,metadata\";\n\n/** What the meeting decided. `kind` is a three-value CHECK constraint (D5). */\nconst NOTE_COLUMNS = \"id,meeting_id,text,kind,assignee_user_id,created_at,metadata\";\n\n/**\n * WHO WAS THERE. The row survives the room, which is the whole point: an\n * attendance list that only exists while LiveKit holds the room is not a record\n * of anything (MRI-D2).\n */\nconst ATTENDEE_COLUMNS =\n \"id,meeting_id,identity,participant_user_id,display_name,avatar_url,role,\" +\n \"admission_state,is_agent,joined_at,left_at\";\n\ntype Row = Record<string, unknown>;\n\nfunction text(row: Row, key: string): string | null {\n const value = row[key];\n return typeof value === \"string\" && value.length > 0 ? value : null;\n}\n\nfunction requireText(row: Row, key: string, operation: string): string {\n const value = text(row, key);\n if (value === null) {\n throw invalidResponse(operation, `the row is missing \"${key}\"`);\n }\n return value;\n}\n\nfunction bool(row: Row, key: string, fallback: boolean): boolean {\n const value = row[key];\n return typeof value === \"boolean\" ? value : fallback;\n}\n\nfunction stringArray(row: Row, key: string): readonly string[] {\n const value = row[key];\n if (!Array.isArray(value)) return [];\n return value.filter((entry): entry is string => typeof entry === \"string\");\n}\n\nconst CALL_STATES: readonly CallState[] = [\n \"idle\",\n \"dialing\",\n \"ringing\",\n \"connecting\",\n \"active\",\n \"declined\",\n \"missed\",\n \"busy\",\n \"cancelled\",\n \"ended\",\n \"failed\",\n];\n\nfunction callState(value: string | null): CallState {\n return CALL_STATES.includes(value as CallState) ? (value as CallState) : \"failed\";\n}\n\nexport interface CreateCallInviteInput {\n readonly roomName: RoomName;\n readonly mode: CallMode;\n readonly callerUserId: UserId;\n readonly callerName: string;\n readonly callerAvatarUrl: string | null;\n readonly calleeUserIds: readonly UserId[];\n readonly organizationId: OrganizationId;\n readonly conversationId: string | null;\n readonly expiresAt: string;\n}\n\nexport interface CreateMeetingInput {\n readonly organizationId: OrganizationId;\n readonly hostUserId: UserId;\n readonly title: string;\n readonly kind: MeetingKind;\n readonly scheduledFor?: string | null;\n readonly scheduledDurationMinutes?: number | null;\n readonly lobbyEnabled?: boolean;\n readonly recordingPolicy?: RecordingPolicy;\n readonly aiEnabled?: boolean;\n /** Reuse a durable slug (a recurring meeting keeps ONE link — R3). */\n readonly slug?: string | undefined;\n}\n\nexport interface MeetRepository {\n readonly schema: string;\n readonly tables: typeof TABLES;\n projectInvite(row: Row): CallInvite;\n projectMeeting(row: Row): MeetingRecord;\n createCallInvite(input: CreateCallInviteInput): Promise<CallInvite>;\n settleCallInvite(id: CallId, state: CallState, declineMessage: string | null): Promise<CallInvite>;\n pendingInvites(userId: UserId): Promise<readonly CallInvite[]>;\n getOrCreateMeeting(input: CreateMeetingInput): Promise<MeetingRecord>;\n meetingBySlug(slug: string): Promise<MeetingRecord>;\n meeting(id: MeetingId): Promise<MeetingRecord>;\n /** Keyset paged, `(scheduled_for, id)`. */\n listMeetings(args: {\n organizationId: OrganizationId;\n limit?: number;\n before?: { scheduledFor: string; id: MeetingId } | null;\n }): Promise<{ readonly items: readonly MeetingRecord[]; readonly hasMore: boolean }>;\n admit(args: {\n meetingId: MeetingId;\n identity: string;\n admitted: boolean;\n byUserId: UserId;\n }): Promise<void>;\n setLock(meetingId: MeetingId, locked: boolean, byUserId: UserId): Promise<MeetingRecord>;\n endMeeting(meetingId: MeetingId, byUserId: UserId): Promise<MeetingRecord>;\n projectSegment(row: Row): TranscriptSegment;\n projectNote(row: Row): MeetingNote;\n /** One `meet_recordings` row, however it arrived (row or room packet). */\n projectRecording(row: Row): RecordingRecord;\n /** One durable `meet_participants` row — attendance, and the lobby queue. */\n projectAttendee(row: Row): MeetingAttendee;\n projectAttendee(row: Row): MeetingAttendee;\n /**\n * WHO ATTENDED, oldest arrival first. Everyone the meeting ever admitted —\n * including the note-taker, which is a labelled participant and never a hidden\n * listener (R4) — so the record can say who was in the room AND that it was\n * transcribed.\n */\n attendees(meetingId: MeetingId): Promise<readonly MeetingAttendee[]>;\n /**\n * THE DURABLE TRANSCRIPT (D16). Final rows only — the table holds nothing\n * else — oldest first, capped so a four-hour meeting cannot hand a surface\n * fifty thousand rows in one read.\n */\n transcript(meetingId: MeetingId, limit?: number): Promise<readonly TranscriptSegment[]>;\n /** Live notes, decisions, action items and the wrap-up summary, oldest first. */\n notes(meetingId: MeetingId): Promise<readonly MeetingNote[]>;\n /** R5: consent is RECORDED, not assumed. One row per participant per recording. */\n recordConsent(args: {\n meetingId: MeetingId;\n identity: string;\n acknowledgedAt: string;\n }): Promise<void>;\n recordings(meetingId: MeetingId): Promise<readonly RecordingRecord[]>;\n /** Meet wave 3: every recording of the reader's own meetings, newest first. */\n myRecordings(args?: { includeArchived?: boolean; limit?: number }): Promise<readonly LibraryRecording[]>;\n /** Meet wave 3: search the reader's own meetings. */\n searchMeetings(query: string, limit?: number): Promise<readonly MeetingSearchHit[]>;\n /** Meet wave 3: name a recording (`null` = back to the meeting's title and date). */\n renameRecording(recordingId: string, title: string | null): Promise<void>;\n /** Meet wave 3: archive (soft delete) or restore a recording. Never a purge. */\n setRecordingArchived(recordingId: string, archived: boolean): Promise<void>;\n\n /* ── MEET WAVE 1 — management (0.8) ── */\n scheduleMeeting(input: ScheduleMeetingInput): Promise<MeetingRecord>;\n /** `expectedVersion` from the row you edited; a stale one is a `conflict`. */\n updateMeeting(\n meetingId: MeetingId,\n changes: MeetingChanges,\n options?: { expectedVersion?: number | null; byUserId?: UserId | null },\n ): Promise<MeetingRecord>;\n cancelMeeting(meetingId: MeetingId, reason: string | null, byUserId?: UserId | null): Promise<MeetingRecord>;\n archiveMeeting(meetingId: MeetingId, byUserId?: UserId | null): Promise<MeetingRecord>;\n restoreMeeting(meetingId: MeetingId, byUserId?: UserId | null): Promise<MeetingRecord>;\n setOccurrence(args: {\n meetingId: MeetingId;\n originalStart: string;\n action: \"cancel\" | \"move\" | \"restore\";\n newStart?: string | null;\n newDurationMinutes?: number | null;\n reason?: string | null;\n byUserId?: UserId | null;\n }): Promise<OccurrenceOverride>;\n meetingOccurrences(\n meetingId: MeetingId,\n range: { from: string; to: string; limit?: number },\n ): Promise<readonly MeetingOccurrence[]>;\n /** The Upcoming list: every occurrence the reader may see. `organizationId` FILTERS; RLS decides. */\n occurrencesBetween(range: {\n from: string;\n to: string;\n organizationId?: OrganizationId | null;\n limit?: number;\n }): Promise<readonly UpcomingOccurrence[]>;\n invitees(meetingId: MeetingId): Promise<readonly MeetingInvitee[]>;\n addInvitees(meetingId: MeetingId, people: readonly InviteeInput[], byUserId?: UserId | null): Promise<readonly MeetingInvitee[]>;\n setInviteeRole(inviteeId: string, role: InviteeRole, byUserId?: UserId | null): Promise<MeetingInvitee>;\n removeInvitee(inviteeId: string, byUserId?: UserId | null): Promise<MeetingInvitee>;\n respond(meetingId: MeetingId, answer: RsvpAnswer, note?: string | null): Promise<MeetingInvitee>;\n invitationByToken(secret: string): Promise<RsvpInvitation>;\n respondByToken(secret: string, answer: RsvpAnswer, note?: string | null): Promise<RsvpInvitation>;\n projectInvitee(row: Row): MeetingInvitee;\n}\n\nexport interface ScheduleMeetingInput {\n readonly organizationId: OrganizationId;\n readonly hostUserId: UserId;\n readonly title: string;\n readonly scheduledFor: string | null;\n /** IANA zone, e.g. `America/Los_Angeles`. The wall-clock time a series keeps across DST. */\n readonly timeZone: string;\n /** Omit to use the person's `meet.default_duration_minutes`. */\n readonly durationMinutes?: number | null | undefined;\n readonly agenda?: string | null | undefined;\n /** RRULE subset: FREQ=DAILY|WEEKLY|MONTHLY, INTERVAL, BYDAY, BYMONTHDAY, COUNT, UNTIL. */\n readonly recurrenceRule?: string | null | undefined;\n readonly settings?: MeetingSettings | undefined;\n}\n\nexport interface RepositoryOptions {\n /**\n * Any Supabase client. Deliberately the SHALLOW public shape — pass the\n * `SupabaseClient<Database>` you already have, with no cast. See the header.\n */\n client: MessagingSupabaseClient;\n /** Resolve a session; used to retry ONCE across the sign-in gap. */\n session?: (() => Promise<unknown>) | undefined;\n}\n\n/**\n * 🚨 THE PROJECTIONS ARE MODULE-LEVEL AND EXPORTED, DELIBERATELY (MRI-A12).\n *\n * A durable Meet row reaches a client on one of two transports: as a\n * `meet_notes` / `meet_transcript_segments` row over Postgres Changes, which\n * needs a Supabase session and an org grant, or as a `matrx.meet.*` packet on\n * the LiveKit data plane, which needs only the room token — and is therefore the\n * ONLY one a session-less guest can receive (MRI-A10 settled that `anon` never\n * gets a grant on an org-scoped table).\n *\n * Both carry the same row. If each transport projected it with its own function,\n * a guest and a member would render the same meeting differently the first time\n * the two drifted. So there is one function per row shape, it takes no client,\n * and `core/room-events.ts` calls exactly these.\n */\nexport function projectSegment(row: Row): TranscriptSegment {\n const operation = \"meet.projectSegment\";\n const id = requireText(row, \"id\", operation);\n return {\n id,\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n identity: asParticipantIdentity(text(row, \"identity\") ?? \"unknown\"),\n // A nameless line is a line nobody can act on. The identity is a worse\n // name than a real one and a far better one than an empty string.\n speaker: text(row, \"speaker\") ?? text(row, \"identity\") ?? \"Someone\",\n text: text(row, \"text\") ?? \"\",\n startedAt: text(row, \"started_at\") ?? new Date(0).toISOString(),\n // The table holds finals only; a row that somehow says otherwise is still\n // a durable record and is rendered as one.\n final: bool(row, \"is_final\", true),\n source: \"record\",\n // The worker publishes the caption under THIS row's id (`lk.segment_id` =\n // the durable segment id), which is what lets a record replace the exact\n // caption it supersedes instead of doubling the line (D16).\n captionId: id,\n };\n}\n\nexport function projectNote(row: Row): MeetingNote {\n const operation = \"meet.projectNote\";\n const kind = text(row, \"kind\");\n const rawMetadata = row[\"metadata\"];\n const metadata: Record<string, unknown> =\n typeof rawMetadata === \"object\" && rawMetadata !== null && !Array.isArray(rawMetadata)\n ? (rawMetadata as Record<string, unknown>)\n : {};\n const assignee = metadata[\"assignee\"];\n const assigneeRow: Record<string, unknown> =\n typeof assignee === \"object\" && assignee !== null && !Array.isArray(assignee)\n ? (assignee as Record<string, unknown>)\n : {};\n const windowValue = metadata[\"window\"];\n const windowRow: Record<string, unknown> =\n typeof windowValue === \"object\" && windowValue !== null && !Array.isArray(windowValue)\n ? (windowValue as Record<string, unknown>)\n : {};\n const assigneeUserId = text(row, \"assignee_user_id\");\n const displayName = assigneeRow[\"display_name\"];\n return {\n id: requireText(row, \"id\", operation),\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n text: (text(row, \"text\") ?? \"\").trim(),\n createdAt: text(row, \"created_at\") ?? new Date().toISOString(),\n // An unknown kind is a NOTE, never dropped: a row the database accepted\n // is a row a person wrote down, whatever a future migration calls it.\n kind:\n kind === \"decision\" || kind === \"action-item\" ? (kind as MeetingNote[\"kind\"]) : \"note\",\n assigneeUserId: assigneeUserId === null ? null : asUserId(assigneeUserId),\n // D18: a guest never gets an `assignee_user_id` (the FK targets\n // `auth.users`), so their name lives in the metadata and is read here —\n // an action item whose owner has no name is an action item nobody owns.\n assigneeDisplayName:\n typeof displayName === \"string\" && displayName.length > 0 ? displayName : null,\n role: metadata[\"role\"] === \"summary\" ? \"summary\" : null,\n window: typeof windowRow[\"index\"] === \"number\" ? windowRow[\"index\"] : null,\n // D20. `superseded_by` is in `NOTE_PUBLIC_METADATA_KEYS` server-side, so a\n // session-less guest's room-borne copy carries it too — otherwise the guest\n // would be the one lane still reading a decision twice.\n supersededBy:\n typeof metadata[\"superseded_by\"] === \"string\" && metadata[\"superseded_by\"].length > 0\n ? (metadata[\"superseded_by\"] as string)\n : null,\n // THE DATABASE ROW. `core/room-events.ts` marks its copy of the same row\n // `\"room\"`, and the store's precedence rule reads this field (MRI-A12).\n source: \"record\",\n };\n}\n\n\n\n/* ─────────────────────────────── MEET WAVE 1 — management projections (0.8) */\n\nconst RSVP_STATES: readonly RsvpState[] = [\"needs_action\", \"accepted\", \"declined\", \"tentative\"];\nconst OCCURRENCE_STATES: readonly OccurrenceState[] = [\"scheduled\", \"moved\", \"cancelled\"];\n\nfunction rsvpState(value: string | null): RsvpState {\n return RSVP_STATES.includes(value as RsvpState) ? (value as RsvpState) : \"needs_action\";\n}\n\nfunction num(row: Row, key: string): number | null {\n const value = row[key];\n return typeof value === \"number\" ? value : null;\n}\n\n/** A database timestamp as ISO text. PostgREST sends strings; a test double may send Dates. */\nfunction when(row: Row, key: string): string | null {\n const value = row[key];\n if (value instanceof Date) return value.toISOString();\n return text(row, key);\n}\n\nexport function projectInvitee(row: Row): MeetingInvitee {\n const operation = \"meet.projectInvitee\";\n const userId = text(row, \"invitee_user_id\");\n return {\n id: requireText(row, \"id\", operation),\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n userId: userId === null ? null : asUserId(userId),\n email: text(row, \"email\"),\n displayName: text(row, \"display_name\"),\n role: text(row, \"role\") === \"cohost\" ? \"cohost\" : \"invitee\",\n rsvpState: rsvpState(text(row, \"rsvp_state\")),\n respondedAt: when(row, \"responded_at\"),\n rsvpNote: text(row, \"rsvp_note\"),\n lastSentSequence: num(row, \"last_sent_sequence\"),\n lastSentAt: when(row, \"last_sent_at\"),\n };\n}\n\nexport function projectOccurrence(row: Row): MeetingOccurrence {\n const operation = \"meet.projectOccurrence\";\n const state = text(row, \"state\");\n return {\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n originalStart: when(row, \"original_start\") ?? requireText(row, \"original_start\", operation),\n occurrenceStart: when(row, \"occurrence_start\") ?? requireText(row, \"occurrence_start\", operation),\n durationMinutes: num(row, \"duration_minutes\"),\n // An unknown state is shown as scheduled, never dropped: the row is real.\n state: OCCURRENCE_STATES.includes(state as OccurrenceState) ? (state as OccurrenceState) : \"scheduled\",\n sequence: num(row, \"sequence\") ?? 0,\n };\n}\n\nexport function projectUpcoming(row: Row): UpcomingOccurrence {\n const operation = \"meet.projectUpcoming\";\n const kind = text(row, \"kind\");\n const myRole = text(row, \"my_role\");\n const myRsvp = text(row, \"my_rsvp\");\n return {\n ...projectOccurrence(row),\n organizationId: asOrganizationId(requireText(row, \"organization_id\", operation)),\n title: text(row, \"title\") ?? \"Meeting\",\n slug: requireText(row, \"slug\", operation),\n kind: kind === \"scheduled\" || kind === \"recurring\" ? (kind as MeetingKind) : \"instant\",\n hostUserId: asUserId(requireText(row, \"host_user_id\", operation)),\n timeZone: text(row, \"time_zone\") ?? \"UTC\",\n meetingCancelled: bool(row, \"meeting_cancelled\", false),\n myRsvp: myRsvp === null ? null : rsvpState(myRsvp),\n myRole: myRole === \"host\" || myRole === \"cohost\" || myRole === \"invitee\" ? myRole : null,\n };\n}\n\nexport function projectOverride(row: Row): OccurrenceOverride {\n const operation = \"meet.projectOverride\";\n return {\n id: requireText(row, \"id\", operation),\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n originalStart: when(row, \"original_start\") ?? requireText(row, \"original_start\", operation),\n state: text(row, \"state\") === \"moved\" ? \"moved\" : \"cancelled\",\n newStart: when(row, \"new_start\"),\n newDurationMinutes: num(row, \"new_duration_minutes\"),\n reason: text(row, \"reason\"),\n calendarSequence: num(row, \"calendar_sequence\") ?? 0,\n deletedAt: when(row, \"deleted_at\"),\n };\n}\n\n/** The jsonb the RSVP doors return, typed. A body that is neither shape is refused loudly. */\nexport function projectRsvpInvitation(body: unknown): RsvpInvitation {\n const operation = \"meet.projectRsvpInvitation\";\n if (typeof body !== \"object\" || body === null) {\n throw invalidResponse(operation, \"the RSVP door returned no object\");\n }\n const row = body as Row;\n if (row[\"ok\"] !== true) {\n return {\n ok: false,\n message: text(row, \"message\") ?? \"This invitation link is no longer valid — ask the host to send it again.\",\n };\n }\n const meeting = (row[\"meeting\"] ?? {}) as Row;\n const invitee = (row[\"invitee\"] ?? {}) as Row;\n return {\n ok: true,\n meeting: {\n title: text(meeting, \"title\") ?? \"Meeting\",\n slug: requireText(meeting, \"slug\", operation),\n scheduledFor: when(meeting, \"scheduled_for\"),\n durationMinutes: num(meeting, \"duration_minutes\"),\n timeZone: text(meeting, \"time_zone\") ?? \"UTC\",\n agenda: text(meeting, \"agenda\"),\n recurrenceRule: text(meeting, \"recurrence_rule\"),\n cancelledAt: when(meeting, \"cancelled_at\"),\n cancellationReason: text(meeting, \"cancellation_reason\"),\n endedAt: when(meeting, \"ended_at\"),\n },\n invitee: {\n displayName: text(invitee, \"display_name\"),\n email: text(invitee, \"email\"),\n rsvpState: rsvpState(text(invitee, \"rsvp_state\")),\n respondedAt: when(invitee, \"responded_at\"),\n },\n };\n}\n\n/** Settings → the door's snake_case object, carrying ONLY what was set. */\nexport function settingsPatch(settings: MeetingSettings): Record<string, unknown> {\n const patch: Record<string, unknown> = {};\n if (settings.lobbyEnabled !== undefined) patch[\"lobby_enabled\"] = settings.lobbyEnabled;\n if (settings.recordingPolicy !== undefined) patch[\"recording_policy\"] = settings.recordingPolicy;\n if (settings.aiEnabled !== undefined) patch[\"ai_enabled\"] = settings.aiEnabled;\n if (settings.joinBeforeHost !== undefined) patch[\"join_before_host\"] = settings.joinBeforeHost;\n return patch;\n}\n\n/**\n * A partial edit → the `meet_update_meeting` patch. `undefined` = leave alone,\n * `null` = clear — the difference a JSON patch exists to carry.\n */\nexport function changesPatch(changes: MeetingChanges): Record<string, unknown> {\n const patch = settingsPatch(changes);\n if (changes.title !== undefined) patch[\"title\"] = changes.title;\n if (changes.agenda !== undefined) patch[\"agenda\"] = changes.agenda;\n if (changes.timeZone !== undefined) patch[\"time_zone\"] = changes.timeZone;\n if (changes.scheduledFor !== undefined) patch[\"scheduled_for\"] = changes.scheduledFor;\n if (changes.scheduledDurationMinutes !== undefined) {\n patch[\"scheduled_duration_minutes\"] = changes.scheduledDurationMinutes;\n }\n if (changes.recurrenceRule !== undefined) patch[\"recurrence_rule\"] = changes.recurrenceRule;\n return patch;\n}\n\nexport function createMeetRepository(options: RepositoryOptions): MeetRepository {\n // THE ONE NARROWING, in-package. Everything below works against the rich\n // internal contract; no consumer ever has to satisfy it.\n const db = (options.client as SupabaseLike).schema(MEET_SCHEMA);\n\n /**\n * 🚨 A `RETURNS void` RPC RESOLVES TO `null`, AND THAT IS SUCCESS.\n *\n * `guard` below treats a null `data` as an invalid response, which is right\n * for every RPC that returns a row and CATASTROPHIC for one that returns\n * nothing: `communication.meet_admit_participant` and `meet_record_consent`\n * are both `RETURNS void`, so from the day this package shipped, admitting\n * somebody from the lobby and recording consent BOTH performed their write\n * and then threw \"the database returned no row\" on the way back — the write\n * landed, the client believed it failed, the broadcast that tells the guest\n * never went out, and the guest sat in the waiting room forever. Found in a\n * browser (MRI-A11); the RPC return types are pinned in `VOID_RPCS` below so\n * a future void RPC cannot be wired to the wrong guard by accident.\n */\n async function guardVoid(\n operation: string,\n run: () => PromiseLike<{ data: unknown; error: { message: string; code?: string } | null }>,\n ): Promise<void> {\n let response = await run();\n if (response.error !== null) {\n const normalized = normalizeMeetError(response.error, operation);\n if (normalized.code === \"session-unavailable\" && options.session !== undefined) {\n await options.session();\n response = await run();\n }\n if (response.error !== null) throw normalizeMeetError(response.error, operation);\n }\n // No row is expected and none is read. The absence of an error IS the\n // result — anything else would be inventing a postcondition the database\n // never promised.\n }\n\n async function guard<T>(operation: string, run: () => PromiseLike<{ data: T | null; error: { message: string; code?: string } | null }>): Promise<T> {\n let response = await run();\n if (response.error !== null) {\n const normalized = normalizeMeetError(response.error, operation);\n // ONE retry, and only for the sign-in gap. A permission denial is NEVER\n // retried — retrying one is how a request storm is built.\n if (normalized.code === \"session-unavailable\" && options.session !== undefined) {\n await options.session();\n response = await run();\n }\n if (response.error !== null) throw normalizeMeetError(response.error, operation);\n }\n if (response.data === null) {\n throw invalidResponse(operation, \"the database returned no row\");\n }\n return response.data;\n }\n\n function projectInvite(row: Row): CallInvite {\n const operation = \"meet.projectInvite\";\n const mode = text(row, \"mode\");\n return {\n id: asCallId(requireText(row, \"id\", operation)),\n organizationId: asOrganizationId(requireText(row, \"organization_id\", operation)),\n roomName: asRoomName(requireText(row, \"room_name\", operation)),\n mode: mode === \"video\" ? \"video\" : \"audio\",\n callerUserId: asUserId(requireText(row, \"caller_user_id\", operation)),\n callerName: text(row, \"caller_name\") ?? \"Someone\",\n callerAvatarUrl: text(row, \"caller_avatar_url\"),\n calleeUserIds: stringArray(row, \"callee_ids\").map(asUserId),\n conversationId: text(row, \"conversation_id\"),\n createdAt: requireText(row, \"created_at\", operation),\n expiresAt: text(row, \"expires_at\") ?? requireText(row, \"created_at\", operation),\n state: callState(text(row, \"state\")),\n declineMessage: text(row, \"decline_message\"),\n };\n }\n\n function projectMeeting(row: Row): MeetingRecord {\n const operation = \"meet.projectMeeting\";\n const kind = text(row, \"kind\");\n const policy = text(row, \"recording_policy\");\n const duration = row[\"scheduled_duration_minutes\"];\n const metadata = row[\"metadata\"];\n return {\n id: asMeetingId(requireText(row, \"id\", operation)),\n organizationId: asOrganizationId(requireText(row, \"organization_id\", operation)),\n roomName: asRoomName(requireText(row, \"room_name\", operation)),\n slug: requireText(row, \"slug\", operation),\n title: text(row, \"title\") ?? \"Meeting\",\n kind: kind === \"scheduled\" || kind === \"recurring\" ? (kind as MeetingKind) : \"instant\",\n hostUserId: asUserId(requireText(row, \"host_user_id\", operation)),\n scheduledFor: text(row, \"scheduled_for\"),\n scheduledDurationMinutes: typeof duration === \"number\" ? duration : null,\n startedAt: text(row, \"started_at\"),\n endedAt: text(row, \"ended_at\"),\n locked: bool(row, \"locked\", false),\n lobbyEnabled: bool(row, \"lobby_enabled\", true),\n recordingPolicy:\n policy === \"disabled\" || policy === \"always-on\"\n ? (policy as RecordingPolicy)\n : \"host-controlled\",\n aiEnabled: bool(row, \"ai_enabled\", true),\n metadata:\n typeof metadata === \"object\" && metadata !== null && !Array.isArray(metadata)\n ? (metadata as JsonObject)\n : {},\n timeZone: text(row, \"time_zone\") ?? \"UTC\",\n agenda: text(row, \"agenda\"),\n recurrenceRule: text(row, \"recurrence_rule\"),\n joinBeforeHost: bool(row, \"join_before_host\", true),\n cancelledAt: text(row, \"cancelled_at\"),\n cancellationReason: text(row, \"cancellation_reason\"),\n deletedAt: text(row, \"deleted_at\"),\n calendarSequence: typeof row[\"calendar_sequence\"] === \"number\" ? row[\"calendar_sequence\"] : 0,\n version: typeof row[\"version\"] === \"number\" ? row[\"version\"] : 1,\n };\n }\n\n function projectRecording(row: Row): RecordingRecord {\n const operation = \"meet.projectRecording\";\n const state = text(row, \"state\");\n const known: readonly RecordingState[] = [\n \"idle\",\n \"starting\",\n \"recording\",\n \"stopping\",\n \"processing\",\n \"available\",\n \"expired\",\n \"failed\",\n ];\n return {\n id: requireText(row, \"id\", operation),\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n state: known.includes(state as RecordingState) ? (state as RecordingState) : \"failed\",\n startedAt: text(row, \"started_at\"),\n endedAt: text(row, \"ended_at\"),\n startedBy: text(row, \"started_by\") === null ? null : asUserId(text(row, \"started_by\") as string),\n // A PLATFORM file id, never a provider URL (R3). A recording that only\n // exists as a LiveKit URL is orphaned the day the room is garbage\n // collected, which is the whole reason this column is not `url`.\n fileId: text(row, \"file_id\"),\n failureReason: text(row, \"failure_reason\"),\n retention: projectRecordingRetention(row[\"metadata\"]),\n };\n }\n\n function projectRecordingRetention(value: unknown): RecordingRetention | null {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return null;\n const retention = (value as Record<string, unknown>)[\"retention\"];\n if (typeof retention !== \"object\" || retention === null || Array.isArray(retention)) return null;\n const row = retention as Record<string, unknown>;\n const phase = row[\"phase\"];\n const operationId = row[\"operation_id\"];\n const policyId = row[\"policy_id\"];\n const policyUpdatedAt = row[\"policy_updated_at\"];\n const dueAt = row[\"due_at\"];\n const expiredAt = row[\"expired_at\"];\n if (\n (phase !== \"warning\" && phase !== \"expired\") ||\n typeof operationId !== \"string\" ||\n typeof policyId !== \"string\" ||\n typeof policyUpdatedAt !== \"string\" ||\n typeof dueAt !== \"string\" ||\n (expiredAt !== null && typeof expiredAt !== \"string\")\n ) return null;\n return { operationId, policyId, policyUpdatedAt, phase, dueAt, expiredAt };\n }\n\n function projectAttendee(row: Row): MeetingAttendee {\n const operation = \"meet.projectAttendee\";\n const role = text(row, \"role\");\n const admission = text(row, \"admission_state\");\n const known: readonly ParticipantRole[] = [\"host\", \"cohost\", \"participant\", \"guest\"];\n const states: readonly AdmissionState[] = [\"knocking\", \"admitted\", \"denied\", \"removed\"];\n const userId = text(row, \"participant_user_id\");\n const identity = requireText(row, \"identity\", operation);\n return {\n id: requireText(row, \"id\", operation),\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n identity: asParticipantIdentity(identity),\n // A nameless attendee is a row nobody can read. The identity is a worse\n // name than a real one and an infinitely better one than a blank.\n displayName: text(row, \"display_name\") ?? identity,\n avatarUrl: text(row, \"avatar_url\"),\n userId: userId === null ? null : asUserId(userId),\n role: known.includes(role as ParticipantRole) ? (role as ParticipantRole) : \"participant\",\n admissionState: states.includes(admission as AdmissionState)\n ? (admission as AdmissionState)\n : \"admitted\",\n isAgent: bool(row, \"is_agent\", false),\n joinedAt: text(row, \"joined_at\"),\n leftAt: text(row, \"left_at\"),\n };\n }\n\n function requireOrg(organizationId: OrganizationId, operation: string): void {\n if (typeof organizationId !== \"string\" || organizationId.length === 0) {\n throw new MeetError(\n \"misconfigured\",\n `${operation}: no organization_id`,\n \"Every meet write carries an explicit organization_id (R5). The package refuses the \" +\n \"write rather than letting an unscoped row reach the database.\",\n );\n }\n }\n\n return {\n schema: MEET_SCHEMA,\n tables: TABLES,\n projectInvite,\n projectMeeting,\n projectSegment,\n projectNote,\n projectRecording,\n projectAttendee,\n projectInvitee,\n\n async scheduleMeeting(input) {\n requireOrg(input.organizationId, \"meet.scheduleMeeting\");\n const row = await guard<Row>(\"meet.scheduleMeeting\", () =>\n db.rpc<Row>(RPCS.scheduleMeeting, {\n p_organization_id: input.organizationId,\n p_host_user_id: input.hostUserId,\n p_title: input.title,\n p_scheduled_for: input.scheduledFor,\n p_time_zone: input.timeZone,\n p_duration_minutes: input.durationMinutes ?? null,\n p_agenda: input.agenda ?? null,\n p_recurrence_rule: input.recurrenceRule ?? null,\n p_settings: settingsPatch(input.settings ?? {}),\n }),\n );\n return projectMeeting(row);\n },\n\n async updateMeeting(meetingId, changes, options = {}) {\n const row = await guard<Row>(\"meet.updateMeeting\", () =>\n db.rpc<Row>(RPCS.updateMeeting, {\n p_meeting_id: meetingId,\n p_changes: changesPatch(changes),\n p_expected_version: options.expectedVersion ?? null,\n p_by_user_id: options.byUserId ?? null,\n }),\n );\n return projectMeeting(row);\n },\n\n async cancelMeeting(meetingId, reason, byUserId = null) {\n const row = await guard<Row>(\"meet.cancelMeeting\", () =>\n db.rpc<Row>(RPCS.cancelMeeting, {\n p_meeting_id: meetingId,\n p_reason: reason,\n p_by_user_id: byUserId,\n }),\n );\n return projectMeeting(row);\n },\n\n async archiveMeeting(meetingId, byUserId = null) {\n const row = await guard<Row>(\"meet.archiveMeeting\", () =>\n db.rpc<Row>(RPCS.archiveMeeting, { p_meeting_id: meetingId, p_by_user_id: byUserId }),\n );\n return projectMeeting(row);\n },\n\n async restoreMeeting(meetingId, byUserId = null) {\n const row = await guard<Row>(\"meet.restoreMeeting\", () =>\n db.rpc<Row>(RPCS.restoreMeeting, { p_meeting_id: meetingId, p_by_user_id: byUserId }),\n );\n return projectMeeting(row);\n },\n\n async setOccurrence(args) {\n const row = await guard<Row>(\"meet.setOccurrence\", () =>\n db.rpc<Row>(RPCS.setOccurrence, {\n p_meeting_id: args.meetingId,\n p_original_start: args.originalStart,\n p_action: args.action,\n p_new_start: args.newStart ?? null,\n p_new_duration_minutes: args.newDurationMinutes ?? null,\n p_reason: args.reason ?? null,\n p_by_user_id: args.byUserId ?? null,\n }),\n );\n return projectOverride(row);\n },\n\n async meetingOccurrences(meetingId, { from, to, limit = 200 }) {\n const rows = await guard<Row[]>(\"meet.meetingOccurrences\", () =>\n db.rpc<Row[]>(RPCS.meetingOccurrences, {\n p_meeting_id: meetingId,\n p_from: from,\n p_to: to,\n p_limit: limit,\n }),\n );\n return rows.map(projectOccurrence);\n },\n\n async occurrencesBetween({ from, to, organizationId = null, limit = 500 }) {\n const rows = await guard<Row[]>(\"meet.occurrencesBetween\", () =>\n db.rpc<Row[]>(RPCS.occurrencesBetween, {\n p_from: from,\n p_to: to,\n p_organization_id: organizationId,\n p_limit: limit,\n }),\n );\n return rows.map(projectUpcoming);\n },\n\n async invitees(meetingId) {\n const response = await db\n .from<Row>(TABLES.invitees)\n .select(INVITEE_COLUMNS)\n .eq(\"meeting_id\", meetingId)\n .is(\"deleted_at\", null)\n .order(\"created_at\", { ascending: true })\n .order(\"id\", { ascending: true });\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.invitees\");\n return (response.data ?? []).map(projectInvitee);\n },\n\n async addInvitees(meetingId, people, byUserId = null) {\n const rows = await guard<Row[]>(\"meet.addInvitees\", () =>\n db.rpc<Row[]>(RPCS.addInvitees, {\n p_meeting_id: meetingId,\n p_invitees: people.map((person) => ({\n ...(person.userId !== undefined ? { user_id: person.userId } : {}),\n ...(person.email !== undefined ? { email: person.email } : {}),\n ...(person.displayName !== undefined ? { display_name: person.displayName } : {}),\n ...(person.role !== undefined ? { role: person.role } : {}),\n })),\n p_by_user_id: byUserId,\n }),\n );\n return rows.map(projectInvitee);\n },\n\n async setInviteeRole(inviteeId, role, byUserId = null) {\n const row = await guard<Row>(\"meet.setInviteeRole\", () =>\n db.rpc<Row>(RPCS.setInviteeRole, {\n p_invitee_id: inviteeId,\n p_role: role,\n p_by_user_id: byUserId,\n }),\n );\n return projectInvitee(row);\n },\n\n async removeInvitee(inviteeId, byUserId = null) {\n const row = await guard<Row>(\"meet.removeInvitee\", () =>\n db.rpc<Row>(RPCS.removeInvitee, { p_invitee_id: inviteeId, p_by_user_id: byUserId }),\n );\n return projectInvitee(row);\n },\n\n async respond(meetingId, answer, note = null) {\n const row = await guard<Row>(\"meet.respond\", () =>\n db.rpc<Row>(RPCS.respond, {\n p_meeting_id: meetingId,\n p_response: answer,\n p_note: note,\n p_by_user_id: null,\n }),\n );\n return projectInvitee(row);\n },\n\n async invitationByToken(secret) {\n const body = await guard<unknown>(\"meet.invitationByToken\", () =>\n db.rpc<unknown>(RPCS.invitationByToken, { p_secret: secret }),\n );\n return projectRsvpInvitation(body);\n },\n\n async respondByToken(secret, answer, note = null) {\n const body = await guard<unknown>(\"meet.respondByToken\", () =>\n db.rpc<unknown>(RPCS.respondByToken, {\n p_secret: secret,\n p_response: answer,\n p_note: note,\n }),\n );\n return projectRsvpInvitation(body);\n },\n\n async attendees(meetingId) {\n const response = await db\n .from<Row>(TABLES.participants)\n .select(ATTENDEE_COLUMNS)\n .eq(\"meeting_id\", meetingId)\n .order(\"joined_at\", { ascending: true })\n .order(\"id\", { ascending: true });\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.attendees\");\n return (response.data ?? []).map(projectAttendee);\n },\n\n async createCallInvite(input) {\n requireOrg(input.organizationId, \"meet.createCallInvite\");\n const row = await guard<Row>(\"meet.createCallInvite\", () =>\n db.rpc<Row>(RPCS.createCallInvite, {\n p_room_name: input.roomName,\n p_mode: input.mode,\n p_caller_user_id: input.callerUserId,\n p_caller_name: input.callerName,\n p_caller_avatar_url: input.callerAvatarUrl,\n p_callee_ids: input.calleeUserIds,\n p_organization_id: input.organizationId,\n p_conversation_id: input.conversationId,\n p_expires_at: input.expiresAt,\n }),\n );\n return projectInvite(row);\n },\n\n async settleCallInvite(id, state, declineMessage) {\n const row = await guard<Row>(\"meet.settleCallInvite\", () =>\n db.rpc<Row>(RPCS.settleCallInvite, {\n p_invite_id: id,\n p_state: state,\n p_decline_message: declineMessage,\n }),\n );\n return projectInvite(row);\n },\n\n async pendingInvites(userId) {\n const rows = await guard<Row[]>(\"meet.pendingInvites\", () =>\n db.rpc<Row[]>(RPCS.pendingCallInvites, { p_user_id: userId }),\n );\n return rows.map(projectInvite);\n },\n\n async getOrCreateMeeting(input) {\n requireOrg(input.organizationId, \"meet.getOrCreateMeeting\");\n const row = await guard<Row>(\"meet.getOrCreateMeeting\", () =>\n db.rpc<Row>(RPCS.getOrCreateMeeting, {\n p_organization_id: input.organizationId,\n p_host_user_id: input.hostUserId,\n p_title: input.title,\n p_kind: input.kind,\n p_scheduled_for: input.scheduledFor ?? null,\n p_scheduled_duration_minutes: input.scheduledDurationMinutes ?? null,\n p_lobby_enabled: input.lobbyEnabled ?? true,\n p_recording_policy: input.recordingPolicy ?? \"host-controlled\",\n p_ai_enabled: input.aiEnabled ?? true,\n p_slug: input.slug ?? null,\n }),\n );\n return projectMeeting(row);\n },\n\n async meetingBySlug(slug) {\n // A DURABLE LINK RESOLVES BEFORE, DURING, AND AFTER (R3). This RPC is not\n // filtered by `ended_at is null` on purpose: a link that dies the moment\n // the meeting ends breaks every \"here are the notes\" follow-up.\n const row = await guard<Row>(\"meet.meetingBySlug\", () =>\n db.rpc<Row>(RPCS.meetingBySlug, { p_slug: slug }),\n );\n return projectMeeting(row);\n },\n\n async meeting(id) {\n const response = await db\n .from<Row>(TABLES.meetings)\n .select(MEETING_COLUMNS)\n .eq(\"id\", id)\n .single();\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.meeting\");\n if (response.data === null) throw invalidResponse(\"meet.meeting\", \"no such meeting\");\n return projectMeeting(response.data);\n },\n\n async listMeetings({ organizationId, limit = 25, before = null }) {\n requireOrg(organizationId, \"meet.listMeetings\");\n let query = db\n .from<Row>(TABLES.meetings)\n .select(MEETING_COLUMNS)\n .eq(\"organization_id\", organizationId)\n .order(\"scheduled_for\", { ascending: false })\n .order(\"id\", { ascending: false })\n // ASK FOR ONE MORE THAN THE PAGE, so `hasMore` is a fact rather than a\n // guess from \"we got a full page\".\n .limit(limit + 1);\n if (before !== null) {\n query = query.or(\n `scheduled_for.lt.${before.scheduledFor},and(scheduled_for.eq.${before.scheduledFor},id.lt.${before.id})`,\n );\n }\n const response = await query;\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.listMeetings\");\n const rows = response.data ?? [];\n return {\n items: rows.slice(0, limit).map(projectMeeting),\n hasMore: rows.length > limit,\n };\n },\n\n async admit({ meetingId, identity, admitted, byUserId }) {\n await guardVoid(\"meet.admit\", () =>\n db.rpc<Row>(RPCS.admit, {\n p_meeting_id: meetingId,\n p_identity: identity,\n p_admitted: admitted,\n p_by_user_id: byUserId,\n }),\n );\n },\n\n async setLock(meetingId, locked, byUserId) {\n const row = await guard<Row>(\"meet.setLock\", () =>\n db.rpc<Row>(RPCS.setLock, {\n p_meeting_id: meetingId,\n p_locked: locked,\n p_by_user_id: byUserId,\n }),\n );\n return projectMeeting(row);\n },\n\n async endMeeting(meetingId, byUserId) {\n const row = await guard<Row>(\"meet.endMeeting\", () =>\n db.rpc<Row>(RPCS.endMeeting, {\n p_meeting_id: meetingId,\n p_by_user_id: byUserId,\n }),\n );\n return projectMeeting(row);\n },\n\n async transcript(meetingId, limit = 1000) {\n const response = await db\n .from<Row>(TABLES.transcripts)\n .select(SEGMENT_COLUMNS)\n .eq(\"meeting_id\", meetingId)\n .order(\"started_at\", { ascending: true })\n .order(\"id\", { ascending: true })\n .limit(limit);\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.transcript\");\n return (response.data ?? []).map(projectSegment);\n },\n\n async notes(meetingId) {\n const response = await db\n .from<Row>(TABLES.notes)\n .select(NOTE_COLUMNS)\n .eq(\"meeting_id\", meetingId)\n .order(\"created_at\", { ascending: true })\n .order(\"id\", { ascending: true });\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.notes\");\n return (response.data ?? []).map(projectNote);\n },\n\n async recordConsent({ meetingId, identity, acknowledgedAt }) {\n await guardVoid(\"meet.recordConsent\", () =>\n db.rpc<Row>(RPCS.recordConsent, {\n p_meeting_id: meetingId,\n p_identity: identity,\n p_acknowledged_at: acknowledgedAt,\n }),\n );\n },\n\n async recordings(meetingId) {\n const response = await db\n .from<Row>(TABLES.recordings)\n .select(RECORDING_COLUMNS)\n .eq(\"meeting_id\", meetingId)\n // Meet wave 3: an archived recording is off the record as well as the library.\n .is(\"deleted_at\", null)\n .order(\"started_at\", { ascending: false });\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.recordings\");\n return (response.data ?? []).map(projectRecording);\n },\n\n async myRecordings({ includeArchived = false, limit = 200 } = {}) {\n const rows = await guard<Row[]>(\"meet.myRecordings\", () =>\n db.rpc<Row[]>(RPCS.myRecordings, { p_include_archived: includeArchived, p_limit: limit }),\n );\n return rows.map(projectLibraryRecording);\n },\n\n async searchMeetings(query, limit = 60) {\n if (query.trim().length === 0) return [];\n const rows = await guard<Row[]>(\"meet.searchMeetings\", () =>\n db.rpc<Row[]>(RPCS.search, { p_query: query, p_limit: limit }),\n );\n return rows.map(projectSearchHit);\n },\n\n async renameRecording(recordingId, title) {\n const clean = title === null ? null : title.trim().slice(0, 200) || null;\n const response = await db\n .from<Row>(TABLES.recordings)\n .update({ title: clean })\n .eq(\"id\", recordingId)\n .select(\"id\");\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.renameRecording\");\n if ((response.data ?? []).length === 0) {\n throw normalizeMeetError(\n { message: \"permission denied: only the meeting's host or an editor can rename it\", code: \"42501\" },\n \"meet.renameRecording\",\n );\n }\n },\n\n async setRecordingArchived(recordingId, archived) {\n const response = await db\n .from<Row>(TABLES.recordings)\n .update({ deleted_at: archived ? new Date().toISOString() : null })\n .eq(\"id\", recordingId)\n .select(\"id\");\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.setRecordingArchived\");\n if ((response.data ?? []).length === 0) {\n throw normalizeMeetError(\n { message: \"permission denied: only the meeting's host or an editor can archive it\", code: \"42501\" },\n \"meet.setRecordingArchived\",\n );\n }\n },\n };\n}\n\n/** One row of the recordings library (`meet_my_recordings`). */\nexport interface LibraryRecording {\n readonly id: string;\n readonly meetingId: MeetingId;\n readonly meetingTitle: string;\n readonly meetingSlug: string;\n /** The reader's strongest role on the meeting. */\n readonly role: \"host\" | \"cohost\" | \"invitee\" | \"attendee\";\n readonly state: RecordingState;\n /** A name a host gave it; null = show the meeting title. */\n readonly title: string | null;\n readonly fileId: string | null;\n readonly startedAt: string | null;\n readonly endedAt: string | null;\n readonly durationMs: number | null;\n readonly sizeBytes: number | null;\n readonly failureReason: string | null;\n readonly archivedAt: string | null;\n readonly organizationId: OrganizationId;\n}\n\nconst LIBRARY_STATES: readonly RecordingState[] = [\n \"idle\",\n \"starting\",\n \"recording\",\n \"stopping\",\n \"processing\",\n \"available\",\n \"expired\",\n \"failed\",\n];\n\nexport function projectLibraryRecording(row: Row): LibraryRecording {\n const operation = \"meet.projectLibraryRecording\";\n const state = text(row, \"state\");\n const role = text(row, \"my_role\");\n return {\n id: requireText(row, \"recording_id\", operation),\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n meetingTitle: text(row, \"meeting_title\") ?? \"Meeting\",\n meetingSlug: requireText(row, \"meeting_slug\", operation),\n role: role === \"host\" || role === \"cohost\" || role === \"invitee\" ? role : \"attendee\",\n state: LIBRARY_STATES.includes(state as RecordingState) ? (state as RecordingState) : \"failed\",\n title: text(row, \"recording_title\"),\n fileId: text(row, \"file_id\"),\n startedAt: text(row, \"started_at\"),\n endedAt: text(row, \"ended_at\"),\n durationMs: num(row, \"duration_ms\"),\n sizeBytes: num(row, \"size_bytes\"),\n failureReason: text(row, \"failure_reason\"),\n archivedAt: text(row, \"deleted_at\"),\n organizationId: asOrganizationId(requireText(row, \"organization_id\", operation)),\n };\n}\n\n/** Where a search hit was found. */\nexport type MeetingSearchSource =\n | \"title\"\n | \"summary\"\n | \"decision\"\n | \"action_item\"\n | \"note\"\n | \"transcript\";\n\n/** One hit from `meet_search`. `snippet` marks matched words with ⟦ ⟧. */\nexport interface MeetingSearchHit {\n readonly meetingId: MeetingId;\n readonly meetingTitle: string;\n readonly meetingSlug: string;\n readonly meetingAt: string | null;\n readonly source: MeetingSearchSource;\n /** The note or transcript segment id (the meeting id for a title hit). */\n readonly refId: string;\n readonly speaker: string | null;\n readonly snippet: string;\n /** When it was said / written. */\n readonly at: string | null;\n readonly rank: number;\n}\n\nconst SEARCH_SOURCES: readonly MeetingSearchSource[] = [\n \"title\",\n \"summary\",\n \"decision\",\n \"action_item\",\n \"note\",\n \"transcript\",\n];\n\nexport function projectSearchHit(row: Row): MeetingSearchHit {\n const operation = \"meet.projectSearchHit\";\n const source = text(row, \"source\");\n return {\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n meetingTitle: text(row, \"meeting_title\") ?? \"Meeting\",\n meetingSlug: requireText(row, \"meeting_slug\", operation),\n meetingAt: text(row, \"meeting_at\"),\n source: SEARCH_SOURCES.includes(source as MeetingSearchSource)\n ? (source as MeetingSearchSource)\n : \"note\",\n refId: requireText(row, \"ref_id\", operation),\n speaker: text(row, \"speaker\"),\n snippet: text(row, \"snippet\") ?? \"\",\n at: text(row, \"said_at\"),\n rank: num(row, \"rank\") ?? 0,\n };\n}\n\n/** A snippet split into plain and matched runs, for highlighting without HTML. */\nexport function snippetRuns(snippet: string): readonly { readonly text: string; readonly hit: boolean }[] {\n const runs: { text: string; hit: boolean }[] = [];\n const pattern = /⟦([^⟧]*)⟧/g;\n let last = 0;\n for (const match of snippet.matchAll(pattern)) {\n const start = match.index ?? 0;\n if (start > last) runs.push({ text: snippet.slice(last, start), hit: false });\n runs.push({ text: match[1] ?? \"\", hit: true });\n last = start + match[0].length;\n }\n if (last < snippet.length) runs.push({ text: snippet.slice(last), hit: false });\n return runs;\n}\n","/**\n * WHO IS ACTING — read from the session, never from a prop (DD-240).\n *\n * THE CLASS THIS CLOSES. Through 0.5.x `<MeetProvider userId>` took the acting\n * user's id from the host, and every host had the same one source for it: a\n * copy held in its own client state (matrx-frontend's Redux `selectUserId`).\n * That copy is written once, when the app boots, and nothing rewrites it when\n * the domain-wide auth cookie rotates to a different account, when the person\n * signs out in another tab, or when a refresh returns a different subject. The\n * package then went on issuing user-scoped reads on behalf of somebody the\n * session is no longer:\n *\n * `communication.meet_pending_call_invites(p_user_id => <the stale copy>)`\n * → 42501 at HTTP 403, \"meet: the acting user (4cf62e4e…) is not the\n * authenticated user\"\n *\n * Measured on production 2026-09-14 (register DD-238/DD-240): the two rows came\n * from tabs 8.8 h and 32.9 h old, and the id in the argument named a DIFFERENT\n * account from the one the error sink recorded for the same row. The database\n * was right both times. The defect was that a user id can be handed in at all.\n *\n * So there is ONE source now, and it is the client's own session. The same\n * client that mints the JWT on every PostgREST request answers \"who is this?\",\n * so the id in the argument and the id in the token cannot disagree — not\n * because they are kept in step, but because they are the same fact read once.\n *\n * WHAT THIS MODULE IS. A tiny observable over `client.auth`: the current acting\n * user id, a subscription that fires when it changes, and a `resolving` state\n * that is honest about the moment before the first `getSession()` answers.\n *\n * - It is `resolving` until the first read lands. Nothing user-scoped is\n * issued in that window, which is what a page-load race used to spend\n * issuing reads as a user the tab could not prove it was.\n * - `snapshot()` returns THE SAME REFERENCE until the acting user moves\n * (FEATURE.md rule 7b — a `useSyncExternalStore` source that returns a fresh\n * object per call is \"Maximum update depth exceeded\", not a warning).\n * - It NEVER refuses anything on its own authority. It reports who the session\n * says you are; the database remains the only thing that decides what that\n * is allowed to read.\n * - A client with no `auth` at all is a real, named failure with a remedy —\n * never a silent fall back to \"nobody\" (FEATURE.md rule 7).\n *\n * THE CLIENT BOUNDARY STAYS SHALLOW (0.2.1, `repository.ts`'s header). The\n * public prop type is still `MessagingSupabaseClient`, which does not describe\n * `auth` at all — so this module narrows to its own minimal `AuthLike` in ONE\n * place, exactly as `createMeetRepository` narrows to `SupabaseLike`. A real\n * `SupabaseClient` satisfying `AuthLike` is proven at compile time in\n * `supabase-shape.test.ts`.\n */\n\nimport type { MessagingSupabaseClient } from \"@ai-matrx/messaging\";\nimport { asUserId, type UserId } from \"./types\";\n\n/** What a session looks like to this module. Nothing else is read from it. */\nexport interface AuthSessionLike {\n readonly user?: { readonly id?: string | null } | null | undefined;\n}\n\nexport interface AuthSubscriptionLike {\n readonly data: { readonly subscription: { unsubscribe(): void } };\n}\n\n/**\n * The subset of `client.auth` this package uses — the INTERNAL contract, never\n * a public prop type.\n */\nexport interface AuthLike {\n getSession(): PromiseLike<{\n data: { session?: AuthSessionLike | null | undefined };\n }>;\n onAuthStateChange(\n callback: (event: string, session: AuthSessionLike | null) => void,\n ): AuthSubscriptionLike;\n}\n\nexport interface SessionIdentitySnapshot {\n /**\n * `resolving` until the first `getSession()` answers. A user-scoped read\n * issued in this window would be issued on behalf of a guess.\n */\n readonly state: \"resolving\" | \"resolved\";\n /** Who the session says is acting, or `null` for nobody. */\n readonly userId: UserId | null;\n}\n\nexport interface SessionIdentity {\n /** Stable reference until the acting user actually changes (rule 7b). */\n snapshot(): SessionIdentitySnapshot;\n subscribe(listener: () => void): () => void;\n dispose(): void;\n}\n\nexport interface SessionIdentityOptions {\n readonly client: MessagingSupabaseClient;\n readonly onDiagnostic?:\n | ((event: {\n level: \"info\" | \"warn\" | \"error\";\n message: string;\n remedy?: string | undefined;\n }) => void)\n | undefined;\n}\n\nconst RESOLVING: SessionIdentitySnapshot = Object.freeze({\n state: \"resolving\" as const,\n userId: null,\n});\n\n/** The snapshot every server render sees: nobody is acting on a server. */\nexport const SERVER_SESSION_IDENTITY: SessionIdentitySnapshot = RESOLVING;\n\n/**\n * The one narrowing. A client whose `auth` is missing or not shaped like an\n * auth client is a real failure — we say so, and stay `resolved` with nobody\n * acting, which makes the provider inert rather than wrong.\n */\nexport function authOf(client: MessagingSupabaseClient): AuthLike | null {\n const candidate = (client as unknown as { auth?: unknown }).auth;\n if (candidate === null || typeof candidate !== \"object\") return null;\n const auth = candidate as Partial<AuthLike>;\n if (typeof auth.getSession !== \"function\") return null;\n if (typeof auth.onAuthStateChange !== \"function\") return null;\n return auth as AuthLike;\n}\n\nfunction userIdOf(session: AuthSessionLike | null | undefined): UserId | null {\n const id = session?.user?.id;\n return typeof id === \"string\" && id.length > 0 ? asUserId(id) : null;\n}\n\nexport function createSessionIdentity(options: SessionIdentityOptions): SessionIdentity {\n const { client, onDiagnostic } = options;\n const listeners = new Set<() => void>();\n let current: SessionIdentitySnapshot = RESOLVING;\n let disposed = false;\n\n const publish = (state: \"resolving\" | \"resolved\", userId: UserId | null): void => {\n if (disposed) return;\n // SAME REFERENCE until the fact moves (rule 7b).\n if (current.state === state && current.userId === userId) return;\n current = Object.freeze({ state, userId });\n for (const listener of [...listeners]) listener();\n };\n\n const auth = authOf(client);\n if (auth === null) {\n onDiagnostic?.({\n level: \"error\",\n message:\n \"Meet cannot tell who is signed in: the Supabase client it was given has no auth \" +\n \"session source.\",\n remedy:\n \"Pass your app's browser Supabase client to <MeetProvider client={...}> — the same \" +\n \"client it signs in with. Meet reads the acting user from that client's session; \" +\n \"there is no prop for a user id, on purpose.\",\n });\n current = Object.freeze({ state: \"resolved\" as const, userId: null });\n return {\n snapshot: () => current,\n subscribe: (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n dispose: () => {\n disposed = true;\n listeners.clear();\n },\n };\n }\n\n // The first read. `getSession()` awaits auth-js's own initialization and its\n // single-flighted refresh, so this is the same answer the next PostgREST\n // request's JWT will carry.\n void (async () => {\n try {\n const result = await auth.getSession();\n publish(\"resolved\", userIdOf(result?.data?.session));\n } catch (error: unknown) {\n onDiagnostic?.({\n level: \"warn\",\n message: `Meet could not read the signed-in session: ${String(\n (error as Error)?.message ?? error,\n )}`,\n remedy:\n \"Calls and meetings stay unavailable on this device until the session can be read. \" +\n \"Reload the page; if it persists, sign in again.\",\n });\n publish(\"resolved\", null);\n }\n })();\n\n // …and every change after it. A sign-out, an account switch, and a refresh\n // that returns a different subject all land here.\n const subscription = auth.onAuthStateChange((_event, session) => {\n publish(\"resolved\", userIdOf(session));\n });\n\n return {\n snapshot: () => current,\n subscribe: (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n dispose: () => {\n disposed = true;\n listeners.clear();\n try {\n subscription.data.subscription.unsubscribe();\n } catch {\n // An already-torn-down subscription is not a failure worth a sentence.\n }\n },\n };\n}\n","/**\n * THE PLATFORM'S OWN VOICE IN THE ROOM — and the ONLY live feed a guest has.\n *\n * 🚨 **Why this file exists.** Everything durable a meeting produces — a live\n * note, a decision, an action item, the note-taker's state, the ending — lands\n * in `communication.meet_*`, and a signed-in member learns about it over\n * Postgres Changes. A GUEST cannot: `anon` holds no SELECT grant on\n * `meet_notes`, `meet_transcript_segments` or `meet_participants`, and MRI-A10\n * settled that widening it is forbidden, because those are org-scoped tables and\n * a meeting link is not org membership. A guest's authority is the ROOM TOKEN.\n * So the platform publishes the same rows into the room, where the token is the\n * authorization, and this file turns those packets into exactly the same store\n * calls the database path makes.\n *\n * Three rules hold it together:\n *\n * 1. **Same row, same projection, same reducer.** A `matrx.meet.note` packet\n * carries a `meet_notes` row and is projected by `projectNote` — the very\n * function the Postgres Changes handler uses — then handed to\n * `store.upsertNote`. A guest and a member therefore converge on one code\n * path rather than on two implementations that agree until they don't.\n * 2. **Keyed by the row id, so both copies are one thing.** A member receives\n * every note TWICE. They render once because the id is the row's id on both\n * transports, and where the two could disagree the database wins\n * (`store.upsertNote`'s precedence rule, D16).\n * 3. **`matrx.meet.*` is the server's namespace and nothing else's.** LiveKit\n * does not validate a data packet's sender, so any participant could publish\n * any bytes under any topic. What makes these trustworthy is that publishing\n * them requires a `roomAdmin` grant, which only the server's own control\n * token carries — a participant token cannot claim it. The in-room control\n * plane participants DO publish (hand, reaction, chat) lives under `mx.*`\n * and is handled separately, precisely so the two can never be confused.\n */\n\nimport { projectNote } from \"./repository\";\nimport type { MeetStore, RoomChatMessage } from \"./store\";\nimport {\n asMeetingId,\n asParticipantIdentity,\n type JsonObject,\n type MeetingRecord,\n type ParticipantRole,\n type RecordingState,\n type UserId,\n type WrapUpAnnouncement,\n} from \"./types\";\n\n/** Pinned against `RecordingState`; an unknown word is dropped, never shown. */\nconst RECORDING_STATES: readonly RecordingState[] = [\n \"idle\",\n \"starting\",\n \"recording\",\n \"stopping\",\n \"processing\",\n \"available\",\n \"expired\",\n \"failed\",\n];\n\n/**\n * The server's namespace. Pinned against `aidream/services/meet/livekit.py`'s\n * `ROOM_EVENT_PREFIX` — a rename on either side must break a named test here.\n */\nexport const ROOM_EVENT_PREFIX = \"matrx.meet.\";\n\nexport const ROOM_EVENTS = {\n /** One durable `meet_notes` row was written. Payload `{ note: <row> }`. */\n note: \"matrx.meet.note\",\n /** `meet_meetings.metadata.note_taker` changed. Payload `{ meeting_id, note_taker }`. */\n noteTaker: \"matrx.meet.note_taker\",\n /** A wrap-up pass finished. Payload `{ meeting_id, note_ids, segment_count }`. */\n wrapUp: \"matrx.meet.wrap_up\",\n /** The meeting ended for everyone. Payload `{ meeting_id, ended_at, trigger }`. */\n ended: \"matrx.meet.ended\",\n /**\n * A `meet_recordings` row changed state. Payload\n * `{ meeting_id, recording: { id, state, started_by } }`.\n *\n * 🚨 THIS IS THE ONLY WAY A GUEST LEARNS A RECORDING IS RUNNING. PreJoin\n * promises every joiner an indicator, and `anon` holds no SELECT grant on\n * `meet_recordings` (MRI-A10 settled that widening it is forbidden), so\n * without this packet the promise was a sentence with nothing behind it: on\n * production 2026-09-09 the guest lane showed no indicator at all while the\n * host recorded (MRI-C8).\n */\n recording: \"matrx.meet.recording\",\n /**\n * A chat message to everyone was SAVED (Meet wave 2). Payload\n * `{ message: { id, meeting_id, sender_identity, sender_name, body, created_at } }`.\n */\n chat: \"matrx.meet.chat\",\n /**\n * A host or co-host acted (Meet wave 2). Payload `{ meeting_id, kind, … }`:\n * `muted {source, by}` · `ask-unmute {by}` · `removed {by}` — addressed to the\n * person concerned; `lower-hands {identities: [...] | \"*\"}` · `role {identity,\n * role}` — to everyone.\n */\n moderation: \"matrx.meet.moderation\",\n} as const;\n\nexport type RoomEventTopic = (typeof ROOM_EVENTS)[keyof typeof ROOM_EVENTS];\n\nexport function isRoomEventTopic(topic: string): boolean {\n return topic.startsWith(ROOM_EVENT_PREFIX);\n}\n\ntype Payload = Record<string, unknown>;\n\nfunction object(value: unknown): Payload | null {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Payload)\n : null;\n}\n\nfunction text(value: unknown): string | null {\n return typeof value === \"string\" && value.length > 0 ? value : null;\n}\n\n/**\n * What happened to one packet. Returned rather than logged from inside, so the\n * room engine can report a drop with its own diagnostic channel and a test can\n * assert on it — a packet that is silently ignored is indistinguishable from\n * one that never arrived, which is the failure this whole item is about.\n */\nexport interface RoomEventOutcome {\n readonly handled: boolean;\n /** Present when `handled` is false. Says what was wrong, in a sentence. */\n readonly ignored?: string;\n}\n\nconst HANDLED: RoomEventOutcome = { handled: true };\n\nfunction ignored(reason: string): RoomEventOutcome {\n return { handled: false, ignored: reason };\n}\n\nexport interface ApplyRoomEventArgs {\n readonly store: MeetStore;\n readonly topic: string;\n /** The packet's already-parsed JSON body. */\n readonly payload: unknown;\n readonly now?: (() => number) | undefined;\n}\n\n/**\n * Apply one `matrx.meet.*` packet to the store. Never throws.\n *\n * A malformed packet is DROPPED with a reason, never partially applied: half a\n * note on a guest's screen is worse than no note, because the guest cannot tell\n * which half they are missing.\n */\nexport function applyRoomEvent(args: ApplyRoomEventArgs): RoomEventOutcome {\n const { store, topic } = args;\n if (!isRoomEventTopic(topic)) {\n return ignored(`${topic} is not a Meet room event`);\n }\n const payload = object(args.payload);\n if (payload === null) {\n return ignored(`${topic} carried no object payload`);\n }\n const now = args.now ?? (() => Date.now());\n\n switch (topic) {\n case ROOM_EVENTS.note:\n return applyNote(store, payload);\n case ROOM_EVENTS.noteTaker:\n return applyNoteTaker(store, payload);\n case ROOM_EVENTS.wrapUp:\n return applyWrapUp(store, payload, now);\n case ROOM_EVENTS.ended:\n return applyEnded(store, payload);\n case ROOM_EVENTS.recording:\n return applyRecording(store, payload);\n case ROOM_EVENTS.chat:\n return applyChat(store, payload);\n case ROOM_EVENTS.moderation:\n return applyModeration(store, payload, now);\n default:\n // A NEWER SERVER, not a bug. Ignoring an unknown event under our own\n // prefix is what lets the platform ship a new one without breaking every\n // client that has not been redeployed.\n return ignored(`${topic} is not known to this version of @ai-matrx/meet`);\n }\n}\n\nfunction applyNote(store: MeetStore, payload: Payload): RoomEventOutcome {\n const row = object(payload[\"note\"]);\n if (row === null) return ignored(\"a note event with no `note` row\");\n if (text(row[\"id\"]) === null || text(row[\"meeting_id\"]) === null) {\n // Without the row id there is no dedupe key, and appending a note that can\n // never be matched to its database copy is exactly the double-render bug.\n return ignored(\"a note row with no id or meeting_id\");\n }\n const meeting = store.snapshot().meeting;\n if (meeting !== null && row[\"meeting_id\"] !== meeting.id) {\n return ignored(\"a note for a different meeting than this room is showing\");\n }\n try {\n // THE SAME PROJECTION THE DATABASE PATH USES — one definition of what a\n // note row means — re-stamped as the room copy so the store's precedence\n // rule can keep the database's word on top.\n store.upsertNote({ ...projectNote(row), source: \"room\" });\n } catch (error) {\n return ignored(`a note row this client could not read: ${String(error)}`);\n }\n return HANDLED;\n}\n\nfunction applyNoteTaker(store: MeetStore, payload: Payload): RoomEventOutcome {\n const noteTaker = object(payload[\"note_taker\"]);\n if (noteTaker === null) return ignored(\"a note-taker event with no state\");\n const meeting = store.snapshot().meeting;\n if (meeting === null) {\n // An ad-hoc call room has no meeting record to hang the state on, and\n // there is no note-taker in one. Stated, not silent.\n return ignored(\"a note-taker state with no meeting record to attach it to\");\n }\n const meetingId = text(payload[\"meeting_id\"]);\n if (meetingId !== null && meetingId !== meeting.id) {\n return ignored(\"a note-taker state for a different meeting\");\n }\n // MERGED, NOT REPLACED. The packet carries only the `note_taker` object — the\n // two keys a surface renders — because the rest of the row names people and\n // organizations a guest is not authorized to learn. Everything else on the\n // meeting record stays exactly as the join backfill left it.\n const next: MeetingRecord = {\n ...meeting,\n metadata: { ...meeting.metadata, note_taker: noteTaker as JsonObject },\n };\n store.patch({ meeting: next });\n return HANDLED;\n}\n\nfunction applyWrapUp(\n store: MeetStore,\n payload: Payload,\n now: () => number,\n): RoomEventOutcome {\n const meetingId = text(payload[\"meeting_id\"]);\n if (meetingId === null) return ignored(\"a wrap-up event with no meeting id\");\n const meeting = store.snapshot().meeting;\n if (meeting !== null && meetingId !== meeting.id) {\n return ignored(\"a wrap-up for a different meeting\");\n }\n const rawIds = payload[\"note_ids\"];\n const noteIds = Array.isArray(rawIds)\n ? rawIds.filter((value): value is string => typeof value === \"string\")\n : [];\n const segmentCount = payload[\"segment_count\"];\n const announcement: WrapUpAnnouncement = {\n meetingId: asMeetingId(meetingId),\n noteIds,\n segmentCount: typeof segmentCount === \"number\" ? segmentCount : 0,\n at: new Date(now()).toISOString(),\n };\n store.announceWrapUp(announcement);\n return HANDLED;\n}\n\nfunction applyRecording(store: MeetStore, payload: Payload): RoomEventOutcome {\n const row = object(payload[\"recording\"]);\n if (row === null) return ignored(\"a recording event with no `recording` row\");\n const meetingId = text(payload[\"meeting_id\"]);\n const meeting = store.snapshot().meeting;\n if (meeting !== null && meetingId !== null && meetingId !== meeting.id) {\n return ignored(\"a recording state for a different meeting than this room is showing\");\n }\n const state = text(row[\"state\"]);\n if (state === null || !RECORDING_STATES.includes(state as RecordingState)) {\n // An UNKNOWN state is dropped rather than rendered: a recording indicator\n // that says a word nobody defined is worse than one that says nothing.\n return ignored(`a recording state this version does not know: ${String(row[\"state\"])}`);\n }\n const by = text(row[\"started_by\"]);\n // `\"room\"` — the durable row outranks this the moment a member's\n // subscription delivers it (D16, `store.setRecording`).\n store.setRecording(\n state as RecordingState,\n by === null ? null : (by as UserId),\n \"room\",\n text(row[\"id\"]),\n );\n return HANDLED;\n}\n\nfunction applyEnded(store: MeetStore, payload: Payload): RoomEventOutcome {\n const meetingId = text(payload[\"meeting_id\"]);\n const meeting = store.snapshot().meeting;\n if (meeting === null) return ignored(\"an ended event with no meeting record\");\n if (meetingId !== null && meetingId !== meeting.id) {\n return ignored(\"an ended event for a different meeting\");\n }\n // 🚨 THE LAST THING A GUEST HEARS. Ending a meeting deletes the LiveKit room,\n // so the server publishes this in the moment BEFORE the delete — and a client\n // that ignored it would keep saying the meeting is live while everyone is\n // disconnected. The `left` phase that follows says nothing about WHY.\n const endedAt = text(payload[\"ended_at\"]) ?? new Date().toISOString();\n if (meeting.endedAt === endedAt) return HANDLED;\n store.patch({ meeting: { ...meeting, endedAt } });\n return HANDLED;\n}\n\n/** One saved chat row as the room sees it. Shared with the history read. */\nexport function chatFromRow(row: Payload): RoomChatMessage | null {\n const id = text(row[\"id\"]);\n const identity = text(row[\"sender_identity\"]);\n const body = text(row[\"body\"]);\n if (id === null || identity === null || body === null) return null;\n return {\n id,\n identity: asParticipantIdentity(identity),\n displayName: text(row[\"sender_name\"]) ?? \"Participant\",\n text: body,\n at: text(row[\"created_at\"]) ?? new Date().toISOString(),\n // `false` only from a server whose chat table has not landed: the room heard\n // it, nobody will see it later — and the line says so.\n saved: row[\"saved\"] !== false,\n };\n}\n\nfunction applyChat(store: MeetStore, payload: Payload): RoomEventOutcome {\n const row = object(payload[\"message\"]);\n if (row === null) return ignored(\"a chat event with no `message` row\");\n const meeting = store.snapshot().meeting;\n if (meeting !== null && text(row[\"meeting_id\"]) !== null && row[\"meeting_id\"] !== meeting.id) {\n return ignored(\"a chat message for a different meeting\");\n }\n const message = chatFromRow(row);\n if (message === null) return ignored(\"a chat row with no id, sender or body\");\n store.addChat(message);\n return HANDLED;\n}\n\n/** Sentences for what a host did to THIS participant. */\nfunction moderationText(kind: string, payload: Payload): string | null {\n const by = text(payload[\"by\"]) ?? \"The host\";\n switch (kind) {\n case \"muted\": {\n const source = text(payload[\"source\"]) ?? \"microphone\";\n return source === \"microphone\"\n ? `${by} muted you.`\n : source === \"camera\"\n ? `${by} turned off your camera.`\n : `${by} stopped your screen share.`;\n }\n case \"ask-unmute\":\n return `${by} is asking you to unmute.`;\n case \"removed\":\n return `${by} removed you from this meeting.`;\n default:\n return null;\n }\n}\n\nfunction applyModeration(store: MeetStore, payload: Payload, now: () => number): RoomEventOutcome {\n const snapshot = store.snapshot();\n const meetingId = text(payload[\"meeting_id\"]);\n if (snapshot.meeting !== null && meetingId !== null && meetingId !== snapshot.meeting.id) {\n return ignored(\"a moderation event for a different meeting\");\n }\n const kind = text(payload[\"kind\"]);\n switch (kind) {\n case \"lower-hands\": {\n const raw = payload[\"identities\"];\n const everyone = raw === \"*\";\n const named = new Set(\n Array.isArray(raw) ? raw.filter((value): value is string => typeof value === \"string\") : [],\n );\n for (const participant of snapshot.participants) {\n if (participant.handRaised && (everyone || named.has(participant.identity))) {\n store.setHand(participant.identity, false);\n }\n }\n return HANDLED;\n }\n case \"role\": {\n const identity = text(payload[\"identity\"]);\n const role = text(payload[\"role\"]);\n if (identity === null || role === null || !ROLES.includes(role as ParticipantRole)) {\n return ignored(\"a role event with no identity or an unknown role\");\n }\n // THE SERVER CHANGED ITS OWN DECISION. The token's role was minted at join;\n // a co-host made or unmade, or a host handed over, must re-grant or\n // UN-grant this screen's powers now — `effectiveRole` takes the stronger of\n // token and roster, so a demotion that left the token alone would leave the\n // old host holding host controls the server refuses.\n if (identity === snapshot.localIdentity) {\n store.patch({\n grants: { ...snapshot.grants, role: role as ParticipantRole },\n moderationNotice: {\n kind: \"role\",\n text:\n role === \"host\"\n ? \"You are now the host.\"\n : role === \"cohost\"\n ? \"You are now a co-host.\"\n : \"You are no longer a co-host.\",\n at: now(),\n },\n });\n }\n return HANDLED;\n }\n case \"muted\":\n case \"ask-unmute\":\n case \"removed\": {\n const sentence = moderationText(kind, payload);\n if (sentence === null) return ignored(\"a moderation event with no sentence\");\n store.patch({ moderationNotice: { kind, text: sentence, at: now() } });\n return HANDLED;\n }\n default:\n return ignored(`a moderation kind this version does not know: ${String(kind)}`);\n }\n}\n\nconst ROLES: readonly ParticipantRole[] = [\"host\", \"cohost\", \"participant\", \"guest\"];\n","/**\n * THE NOTE-TAKER, AS A SURFACE MUST RENDER IT.\n *\n * 🚨 **THE PACKAGE NEVER GUESSES WHAT THE AGENT IS DOING.** Two facts decide\n * everything here and both come from outside this client: the meeting row's\n * `metadata.note_taker` (written by the server with a CAS, MRI-A2/D9) and\n * whether the agent participant is actually in the LiveKit room. A spinner —\n * \"starting…\" held open by a client-side timer — is the exact lie this file\n * exists to prevent: it survives a worker that never came, a dispatch nobody\n * claimed, and a job that died on a release.\n *\n * 🚨 **A REFUSAL IS RENDERED VERBATIM.** `/agent/start` answers a 503 whose body\n * carries `reason` and `remedy` written by the readiness gate (D7) — \"no worker\n * is registered under matrx-note-taker\", \"every worker is at capacity\",\n * \"the fleet is draining\". Those sentences are the truth about the system and\n * they reach the screen unedited. This package adds no sentence of its own on\n * top of one the server already wrote.\n *\n * The agent's identity is DETERMINISTIC — `agent:note_taker:<meeting_id>` (D9) —\n * which is what makes \"is it in the room\" answerable without a round trip, and\n * what makes a second note-taker impossible to mistake for the first.\n */\n\nimport type { JsonObject, MeetParticipant, MeetingRecord, NoteTakerState } from \"./types\";\n\n/** The one spelling of the agent's participant identity (D9). */\nexport const NOTE_TAKER_IDENTITY_PREFIX = \"agent:note_taker:\";\n\nexport function noteTakerIdentity(meetingId: string): string {\n return `${NOTE_TAKER_IDENTITY_PREFIX}${meetingId}`;\n}\n\n/**\n * The participant attribute the note-taker sets on itself so EVERY client —\n * including one that cannot read the token metadata — knows a notice is owed\n * (D10).\n */\nexport const CONSENT_NOTICE_ATTRIBUTE = \"matrx.agent.consent_notice\";\n\n/** Where the state lives on the meeting row. One spelling, one file. */\nexport const NOTE_TAKER_METADATA_KEY = \"note_taker\";\n\nconst STATES: readonly NoteTakerState[] = [\n \"absent\",\n \"joining\",\n \"transcribing\",\n \"handoff_pending\",\n \"ended\",\n];\n\n/** The server's refusal, as it wrote it. Never paraphrased. */\nexport interface NoteTakerRefusal {\n readonly reason: string;\n readonly remedy: string;\n readonly status: number;\n}\n\nexport interface NoteTakerStatus {\n readonly state: NoteTakerState;\n /** The server's own words for why it is in this state, when it gave any. */\n readonly detail: string | null;\n /** True when the agent participant is in the room RIGHT NOW. */\n readonly present: boolean;\n /** The last dispatch refusal, rendered verbatim. */\n readonly refusal: NoteTakerRefusal | null;\n}\n\nfunction readState(value: unknown): NoteTakerState | null {\n return typeof value === \"string\" && STATES.includes(value as NoteTakerState)\n ? (value as NoteTakerState)\n : null;\n}\n\n/** Is this participant the note-taker (or any agent that owes a notice, D10)? */\nexport function isNoteTaker(participant: MeetParticipant): boolean {\n return (\n participant.identity.startsWith(NOTE_TAKER_IDENTITY_PREFIX) ||\n participant.attributes[CONSENT_NOTICE_ATTRIBUTE] !== undefined ||\n participant.isAgent\n );\n}\n\n/** The agent participant in the room, if any. */\nexport function noteTakerParticipant(\n participants: readonly MeetParticipant[],\n): MeetParticipant | null {\n return participants.find(isNoteTaker) ?? null;\n}\n\n/** The exact deterministic actor whose room presence can corroborate the row. */\nfunction exactNoteTakerParticipant(\n meeting: MeetingRecord | null,\n participants: readonly MeetParticipant[],\n): MeetParticipant | null {\n if (meeting === null) return null;\n const identity = noteTakerIdentity(meeting.id);\n return participants.find((participant) => participant.identity === identity) ?? null;\n}\n\n/**\n * THE STATE, from the two facts that decide it.\n *\n * The durable row is the authority for work. Exact room presence corroborates\n * only a durable `transcribing` state; an arbitrary agent, a consent marker,\n * or a stale note-taker participant never proves speech capture.\n */\nexport function noteTakerStatus(args: {\n meeting: MeetingRecord | null;\n participants: readonly MeetParticipant[];\n refusal?: NoteTakerRefusal | null;\n}): NoteTakerStatus {\n const present = exactNoteTakerParticipant(args.meeting, args.participants) !== null;\n const raw = args.meeting?.metadata[NOTE_TAKER_METADATA_KEY];\n const row: JsonObject =\n typeof raw === \"object\" && raw !== null && !Array.isArray(raw) ? raw : {};\n const recorded = readState(row[\"state\"]);\n const detail = typeof row[\"reason\"] === \"string\" && row[\"reason\"].length > 0\n ? row[\"reason\"]\n : null;\n const refusal = args.refusal ?? null;\n\n if (recorded === null) {\n return { state: \"absent\", detail, present, refusal };\n }\n if (recorded === \"transcribing\" && !present) {\n return { state: \"handoff_pending\", detail, present, refusal };\n }\n return { state: recorded, detail, present, refusal };\n}\n\n/**\n * THE SENTENCE FOR EACH STATE. One place, so the room, the panel and any future\n * surface say the same true thing — and so a state can never render as a bare\n * enum name.\n */\nexport function noteTakerLabel(status: NoteTakerStatus): string {\n switch (status.state) {\n case \"joining\":\n return \"The note-taker is joining this meeting\";\n case \"transcribing\":\n return \"The note-taker is connected and listening for speech\";\n case \"handoff_pending\":\n return \"The note-taker's transcription is interrupted; reconnection is pending\";\n case \"ended\":\n return \"The note-taker has stopped\";\n case \"absent\":\n default:\n return status.present\n ? \"A meeting assistant is connected. Transcription is not confirmed\"\n : \"No note-taker is in this meeting\";\n }\n}\n","/**\n * THE MEDIA SEAM — the ONE interface the room engine talks to.\n *\n * D1/D2: LiveKit Cloud is the media infrastructure, hardcoded. This interface\n * is NOT a provider abstraction and is not here so a second SFU can be swapped\n * in — it exists for two reasons that are both about correctness:\n *\n * 1. **The engine must be provable without a browser.** Everything expensive in\n * a calling product (ring timeouts, reconnection, admission, escalation,\n * speaker tracking) is logic, and logic proven only through a real SFU is\n * logic that is never proven. `testing/fake-driver.ts` drives every one of\n * those paths in a node test.\n * 2. **The SDK stays out of the initial chunk.** `livekit-client` is reached\n * only through a dynamic `import()` inside the default driver, so importing\n * this package during SSR — or on a page with a call BUTTON but no call —\n * costs nothing and touches no browser API.\n *\n * The default implementation ships (`createLiveKitDriver`) and is what\n * `<MeetProvider>` uses when a host injects nothing (THE ALL-INCLUSIVE LAW).\n */\n\nimport type { ConnectionQuality } from \"./types\";\n\n/** A participant as the media layer sees them, before roles or profiles. */\nexport interface DriverParticipant {\n readonly identity: string;\n readonly name: string;\n /** Opaque JSON string the token minted for this participant. */\n readonly metadata: string | null;\n /**\n * The participant's LiveKit attributes. Unlike `metadata` these are set by\n * the participant itself at run time, which is how the note-taker announces\n * that a consent notice is owed (D10).\n */\n readonly attributes: Readonly<Record<string, string>>;\n readonly isLocal: boolean;\n readonly micEnabled: boolean;\n readonly cameraEnabled: boolean;\n readonly screenSharing: boolean;\n}\n\nexport type DriverConnectionState =\n | \"connecting\"\n | \"connected\"\n | \"reconnecting\"\n | \"disconnected\";\n\nexport type DriverTrackKind = \"camera\" | \"microphone\" | \"screen\";\n\n/**\n * ONE LIVE CAPTION off the `lk.transcription` text stream.\n *\n * `speakerIdentity` is `lk.transcribed_participant_identity` — WHO IS BEING\n * TRANSCRIBED, not who published the stream (the note-taker publishes every\n * one of them). The SFU-reported publisher identity below is independently\n * checked against the meeting's note-taker; captions remain hints and durable\n * segments remain the record (D16).\n */\nexport interface DriverTranscription {\n /** `lk.segment_id`. Interim and final share it; that is what makes replacement possible. */\n readonly segmentId: string;\n readonly speakerIdentity: string;\n /**\n * The LiveKit participant that opened this text stream. Unlike\n * `speakerIdentity`, this comes from the SFU and is the authority for who\n * published a caption.\n */\n readonly publisherIdentity: string;\n readonly text: string;\n /** `lk.transcription_final`. */\n readonly final: boolean;\n /** `lk.transcribed_track_id`, when the sender supplied it. */\n readonly trackId: string | null;\n readonly at: string;\n}\n\nexport interface RoomDriverHandlers {\n /** The FULL roster, every time. A delta protocol here drifts; a snapshot cannot. */\n participants(participants: readonly DriverParticipant[]): void;\n activeSpeakers(identities: readonly string[]): void;\n quality(identity: string, quality: ConnectionQuality): void;\n connectionState(state: DriverConnectionState): void;\n /** In-room data messages: hand raise, reactions, in-room chat, AI events. */\n data(topic: string, payload: string, fromIdentity: string | null): void;\n /** A live caption. Interim and final both arrive here (D16). */\n transcription(event: DriverTranscription): void;\n /** The room ended for this client. `reason` is shown to the user verbatim. */\n disconnected(reason: string | null): void;\n /**\n * The ROOM's metadata — set only by the server (`UpdateRoomMetadata`), and\n * delivered to every joiner ON JOIN, which is why the spotlight rides it: a\n * data packet reaches only the people already in the room. Called once after\n * connect and on every change. Optional so an older host driver still works.\n */\n roomMetadata?(metadata: string): void;\n}\n\n/** A camera background effect. `image` replaces the background with `imageUrl`. */\nexport type VideoEffect =\n | { readonly kind: \"none\" }\n | { readonly kind: \"blur\"; readonly radius?: number }\n | { readonly kind: \"image\"; readonly imageUrl: string };\n\n/** Microphone processing the browser applies before anything is sent. */\nexport interface AudioProcessing {\n readonly noiseSuppression: boolean;\n readonly echoCancellation: boolean;\n readonly autoGainControl: boolean;\n}\n\nexport interface MeetRoomDriver {\n connect(serverUrl: string, token: string): Promise<void>;\n disconnect(): Promise<void>;\n setMicrophoneEnabled(enabled: boolean): Promise<void>;\n setCameraEnabled(enabled: boolean): Promise<void>;\n setScreenShareEnabled(enabled: boolean): Promise<void>;\n /**\n * Reliable, topic-addressed data. The in-room control plane. `to` addresses\n * named identities only (a private chat message); absent = everyone.\n */\n publishData(topic: string, payload: string, to?: readonly string[]): Promise<void>;\n /**\n * Apply microphone processing to the live track and to every future one.\n * Optional: a driver without it makes the control ABSENT, never dead.\n */\n setAudioProcessing?(processing: AudioProcessing): Promise<void>;\n /**\n * Apply a background effect to the live camera and to every future one.\n * Rejects with a sentence when this browser cannot run it.\n */\n setVideoEffect?(effect: VideoEffect): Promise<void>;\n /** Whether this browser can run background effects at all. */\n supportsVideoEffects?(): boolean;\n /**\n * Attach a participant's track to a media element. Returns the detach\n * function — returning it (rather than exposing `detach`) is what makes a\n * leaked attachment impossible from the React side: the effect's cleanup IS\n * the return value.\n */\n attach(identity: string, kind: DriverTrackKind, element: HTMLMediaElement): () => void;\n /** The device the driver actually selected, so the UI never lies about it. */\n activeDevices(): Readonly<Record<\"audioinput\" | \"videoinput\" | \"audiooutput\", string | null>>;\n switchDevice(kind: \"audioinput\" | \"videoinput\" | \"audiooutput\", deviceId: string): Promise<void>;\n}\n\nexport type RoomDriverFactory = (\n handlers: RoomDriverHandlers,\n) => MeetRoomDriver | Promise<MeetRoomDriver>;\n\n/** Topics for the in-room control plane. One place, so senders cannot drift. */\nexport const DATA_TOPICS = {\n hand: \"mx.hand\",\n reaction: \"mx.reaction\",\n chat: \"mx.chat\",\n} as const;\n\n/**\n * 🚨 `mx.ai.note` and `mx.ai.transcript` WERE declared here and emitted by\n * nothing. They are gone (MRI-A12): the platform's own events are published by\n * the SERVER under `matrx.meet.*` — see `core/room-events.ts` — because a packet\n * a participant could publish is a packet a guest could forge, and these carry\n * durable rows. A participant topic for the same thing would be a second,\n * unauthenticated way to say it.\n */\n\nexport type DataTopic = (typeof DATA_TOPICS)[keyof typeof DATA_TOPICS];\n\n/**\n * THE LIVEKIT TRANSCRIPTION CONTRACT — not ours, so it is written down once\n * rather than spelled inline. The topic and these four attribute names are the\n * SDK's own (`lk.*`); the worker publishes to exactly them (MRI-A2) and a\n * rename on either side must break here, loudly, in one place.\n */\nexport const TRANSCRIPTION_TOPIC = \"lk.transcription\";\n\nexport const TRANSCRIPTION_ATTRIBUTES = {\n segmentId: \"lk.segment_id\",\n trackId: \"lk.transcribed_track_id\",\n final: \"lk.transcription_final\",\n /**\n * WHO IS BEING TRANSCRIBED. The LiveKit JS client reports the PUBLISHER of a\n * text stream, and the publisher is always the note-taker — so a caption\n * carries the speaker in this attribute and falls back to the publisher only\n * when it is absent (which attributes the line to the agent, visibly, rather\n * than to the wrong person, silently).\n */\n speakerIdentity: \"lk.transcribed_participant_identity\",\n} as const;\n","/**\n * THE ROOM ENGINE — the object a host mounts once and never reasons about.\n *\n * It owns every sequence a calling product gets wrong: ask for a token, connect,\n * project the roster, carry the in-room control plane, keep the phase honest\n * through a reconnect, and tear everything down exactly once. A consumer's job\n * is `engine.join(...)` and rendering a snapshot.\n *\n * THREE rules are structural here, not documented-and-hoped:\n *\n * 1. **The phase never lies.** `connecting` becomes `connected` only when the\n * driver says so, and any failure becomes `failed` WITH the remedy attached\n * to the snapshot. There is no path that leaves a spinner running forever —\n * the single most common complaint about every video product.\n * 2. **Role comes from the TOKEN, never from the client.** A participant's role\n * is read out of the server-minted metadata. A client that could decide it\n * was host could mute anyone; here the claim is unforgeable because the\n * server signed it.\n * 3. **Teardown is idempotent and total.** Leaving twice, or unmounting during\n * a connect, disconnects once and leaves no listener behind. The half-torn\n * room is what produces \"my camera light stays on after the call\".\n */\n\nimport {\n IDLE_TRACK,\n type LocalTrackState,\n unavailableFrom,\n} from \"./attendance\";\nimport { MeetError, normalizeDeviceError, normalizeMeetError } from \"./errors\";\nimport { applyRoomEvent, isRoomEventTopic, ROOM_EVENTS } from \"./room-events\";\nimport { displayNameFor } from \"./names\";\nimport { noteTakerIdentity } from \"./note-taker\";\nimport { captionSegment } from \"./transcript\";\nimport {\n DATA_TOPICS,\n type DriverParticipant,\n type MeetRoomDriver,\n type RoomDriverFactory,\n type RoomDriverHandlers,\n type VideoEffect,\n} from \"./room-driver\";\nimport { type MediaEffects, type MeetStore } from \"./store\";\nimport type { RoomToken, TokenClient } from \"./tokens\";\nimport {\n asParticipantIdentity,\n isHostRole,\n type CallMode,\n type MeetIdentity,\n type MeetingRecord,\n type MeetParticipant,\n type ParticipantIdentity,\n type ParticipantRole,\n type RoomName,\n type StageLayout,\n asUserId,\n type UserId,\n} from \"./types\";\n\nexport interface JoinRequest {\n readonly roomName: RoomName;\n readonly meetingId?: string | undefined;\n readonly slug?: string | undefined;\n /** `audio` joins with the camera off. Same room, same code path (D3). */\n readonly mode: CallMode;\n /**\n * Whether to ATTEMPT the microphone on join. Defaults to true. `false` is a\n * deliberate listen-only join — the pre-join screen's \"Join with microphone\"\n * toggle. Either way the join itself never depends on the outcome; a refused\n * device lands in `snapshot.media.microphone.unavailable`, not in a throw.\n */\n readonly microphone?: boolean | undefined;\n}\n\nexport interface RoomEngineOptions {\n store: MeetStore;\n tokens: TokenClient;\n identity: MeetIdentity;\n driverFactory: RoomDriverFactory;\n /** Canonical public metadata read; room packets alone never authorize teardown. */\n resolveMeeting?: ((slug: string) => Promise<MeetingRecord>) | undefined;\n onDiagnostic?: ((event: { level: \"info\" | \"warn\" | \"error\"; message: string; remedy?: string }) => void) | undefined;\n /** Fired when the local participant leaves for any reason, including kicked. */\n onLeft?: ((reason: string | null) => void) | undefined;\n now?: (() => number) | undefined;\n /** Remembered noise suppression / background choice (Meet wave 2). */\n effectsStorage?: EffectsStorage | undefined;\n /**\n * The device the person PICKED for each kind (the pre-join pickers, the\n * settings panel). Applied before any track is created — through 0.7.x the\n * pickers stored a choice nothing ever read, so every join used the browser\n * default whatever the screen said.\n */\n resolveDevice?: ((kind: \"audioinput\" | \"videoinput\" | \"audiooutput\") => string | null) | undefined;\n}\n\nexport interface RoomEngine {\n join(request: JoinRequest): Promise<void>;\n /**\n * 🚨 THE HOST SAID YES — COME IN.\n *\n * A lobby token is minted with `canPublish: false` and `canSubscribe: false`\n * (that is what makes the lobby real rather than a screen over a live\n * microphone), so admission is not a UI state change: the cached token has to\n * be thrown away and a NEW one minted with the grants the server now gives.\n * Without this the waiting room's own sentence — \"you will join automatically\n * once you are admitted\" — is a lie, and the guest waits forever.\n */\n rejoin(): Promise<void>;\n leave(): Promise<void>;\n setMicrophoneEnabled(enabled: boolean): Promise<void>;\n setCameraEnabled(enabled: boolean): Promise<void>;\n setScreenShareEnabled(enabled: boolean): Promise<void>;\n raiseHand(raised: boolean): Promise<void>;\n react(emoji: string): Promise<void>;\n /**\n * A PRIVATE message to one person (Meet wave 2). Data plane only, addressed\n * to that identity, NEVER saved — see `core/chat.ts` for the saved,\n * everyone-chat, which goes through the server.\n */\n sendPrivateChat(to: ParticipantIdentity, text: string): Promise<void>;\n /**\n * Change this participant's own media processing — noise suppression and the\n * camera background — on the live tracks, and remember it in this browser.\n * A refused effect is a diagnostic and a revert, never a lost camera.\n */\n setEffects(next: Partial<MediaEffects>): Promise<void>;\n /** Whether this browser can run a background effect at all (absent, never dead). */\n supportsVideoEffects(): boolean;\n /** Choose the speaker (audio output) for this meeting. */\n switchDevice(kind: \"audioinput\" | \"videoinput\" | \"audiooutput\", deviceId: string): Promise<void>;\n pin(identity: ParticipantIdentity | null): void;\n setLayout(layout: StageLayout): void;\n attach(\n identity: ParticipantIdentity,\n kind: \"camera\" | \"microphone\" | \"screen\",\n element: HTMLMediaElement,\n ): () => void;\n token(): RoomToken | null;\n dispose(): Promise<void>;\n}\n\n/** Where this browser keeps a participant's media choices. */\nexport interface EffectsStorage {\n load(): MediaEffects;\n save(effects: MediaEffects): void;\n}\n\n/** What the server puts in the token's participant metadata. */\ninterface ParticipantMetadata {\n readonly user_id?: string;\n readonly role?: string;\n readonly can_record?: boolean;\n readonly is_agent?: boolean;\n readonly avatar_url?: string;\n}\n\n/**\n * 🚨 THE SERVER'S WORD, ON TWO CARRIERS (MRI-A11, feedback `7418ef78`).\n *\n * aidream mints the role into the token's participant METADATA (a JSON blob)\n * AND as a LiveKit participant ATTRIBUTE. Both come out of one decision in\n * `services/meet/service.py`; neither can be written by a client. The attribute\n * is preferred because LiveKit delivers the attribute map on every roster\n * update, while a roster event can carry an empty metadata string — which is\n * precisely how, through 2026-09-08, EVERY participant projected as\n * \"participant\" and no host ever saw a host control in a browser.\n *\n * These strings are pinned on the server side too: `test_meet_service.py` reads\n * them out of THIS file and fails if the two sides drift.\n */\nexport const PARTICIPANT_ROLE_ATTRIBUTE = \"matrx.participant.role\";\nexport const PARTICIPANT_CAN_RECORD_ATTRIBUTE = \"matrx.participant.can_record\";\n\nconst KNOWN_ROLES: readonly ParticipantRole[] = [\"host\", \"cohost\", \"participant\", \"guest\"];\n\n/**\n * An unrecognized role is `participant` — never `host`. A word this package\n * does not know is a server that is ahead of it, and the safe reading of an\n * unknown claim is the one that grants nothing.\n */\nfunction parseRole(value: string | undefined): ParticipantRole {\n return KNOWN_ROLES.includes(value as ParticipantRole) ? (value as ParticipantRole) : \"participant\";\n}\n\n/**\n * Metadata is SERVER-MINTED and therefore trusted; it is still parsed\n * defensively, because a malformed blob must degrade a tile to \"participant\"\n * rather than throw inside a roster event and freeze the whole grid.\n */\nexport function projectParticipant(\n driver: DriverParticipant,\n joinedAt: string,\n): MeetParticipant {\n let metadata: ParticipantMetadata = {};\n if (driver.metadata !== null && driver.metadata.length > 0) {\n try {\n const parsed: unknown = JSON.parse(driver.metadata);\n if (typeof parsed === \"object\" && parsed !== null) {\n metadata = parsed as ParticipantMetadata;\n }\n } catch {\n metadata = {};\n }\n }\n const userId = typeof metadata.user_id === \"string\" ? asUserId(metadata.user_id) : null;\n return {\n identity: asParticipantIdentity(driver.identity),\n userId,\n // 🚨 A RAW LIVEKIT IDENTITY IS NEVER A NAME (MRI-A18). Through 0.4.12 this\n // line read `driver.name.length > 0 ? driver.name : driver.identity`, and\n // that single fallback put `guest:v-spk-1` on the participant strip, the\n // People panel, the meeting header and every Pin/Mute aria-label, in BOTH\n // lanes — inside the very structure `core/names.ts` is taught from. A\n // nameless tile is still a bug report nobody can action, so the fallback\n // stays; it is now the name book's HONEST placeholder (\"Unnamed guest\", or\n // the agent's product name) instead of the token. `store.setParticipants`\n // then upgrades this to the best name anything has ever learned.\n displayName: displayNameFor({}, driver.identity, driver.name),\n avatarUrl: typeof metadata.avatar_url === \"string\" ? metadata.avatar_url : null,\n // ATTRIBUTE FIRST, metadata second — see the constants above. Both are the\n // server's; the attribute is simply the one that always arrives.\n role: parseRole(driver.attributes[PARTICIPANT_ROLE_ATTRIBUTE] ?? metadata.role),\n canRecord:\n driver.attributes[PARTICIPANT_CAN_RECORD_ATTRIBUTE] === \"true\" ||\n metadata.can_record === true,\n isLocal: driver.isLocal,\n isAgent: metadata.is_agent === true,\n attributes: driver.attributes,\n micEnabled: driver.micEnabled,\n cameraEnabled: driver.cameraEnabled,\n screenSharing: driver.screenSharing,\n speaking: false,\n handRaised: false,\n quality: \"unknown\",\n joinedAt,\n };\n}\n\ninterface DataEnvelope {\n readonly id?: string;\n readonly at?: string;\n /** Epoch ms a hand went up — the queue's order. */\n readonly raisedAt?: number;\n /** A private chat message's addressee. */\n readonly to?: string;\n readonly raised?: boolean;\n readonly emoji?: string;\n readonly text?: string;\n readonly name?: string;\n}\n\nexport function createRoomEngine(options: RoomEngineOptions): RoomEngine {\n const { store, tokens, identity } = options;\n const now = options.now ?? (() => Date.now());\n let driver: MeetRoomDriver | null = null;\n let current: RoomToken | null = null;\n let joining: Promise<void> | null = null;\n // The request this engine last joined with, so an admitted guest can be let\n // in without the surface having to remember how it got here.\n let lastRequest: JoinRequest | null = null;\n let disposed = false;\n const confirmingEnds = new WeakSet<MeetRoomDriver>();\n\n async function leaveRoom(): Promise<void> {\n const target = driver;\n driver = null;\n if (current !== null) {\n tokens.invalidate(current.roomName);\n current = null;\n }\n store.setLocalTrack(\"microphone\", IDLE_TRACK);\n store.setLocalTrack(\"camera\", IDLE_TRACK);\n store.patch({ phase: \"left\" });\n await target?.disconnect();\n }\n\n async function confirmMeetingEnd(): Promise<void> {\n const meeting = store.snapshot().meeting;\n const target = driver;\n if (meeting === null || target === null || confirmingEnds.has(target) || options.resolveMeeting === undefined) return;\n confirmingEnds.add(target);\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const verified = await Promise.race([\n options.resolveMeeting(meeting.slug),\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(\"Meeting end verification timed out\")), 5000);\n }),\n ]);\n if (disposed || driver !== target || store.snapshot().meeting?.id !== meeting.id) return;\n if (verified.id !== meeting.id || verified.roomName !== meeting.roomName || verified.endedAt === null) {\n report(\"warn\", \"Meet ignored an unconfirmed meeting-end notice\", \"The canonical meeting is still live or does not match this room.\");\n return;\n }\n // Keep newer roster/metadata updates; only the durable ending is needed.\n const latest = store.snapshot().meeting;\n if (latest === null) return;\n store.patch({ meeting: { ...latest, endedAt: verified.endedAt } });\n await leaveRoom();\n } catch (error) {\n report(\"error\", `Meet could not confirm or finish meeting teardown: ${String(error)}`, \"Check the meeting link again; if media remains active, close this meeting tab.\");\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n confirmingEnds.delete(target);\n }\n }\n\n function report(level: \"info\" | \"warn\" | \"error\", message: string, remedy?: string): void {\n options.onDiagnostic?.(remedy === undefined ? { level, message } : { level, message, remedy });\n }\n\n function fail(error: unknown, operation: string): MeetError {\n const normalized = normalizeMeetError(error, operation);\n store.patch({\n phase: \"failed\",\n failure: { message: normalized.message, remedy: normalized.remedy },\n });\n report(\n normalized.code === \"session-unavailable\" ? \"warn\" : \"error\",\n normalized.message,\n normalized.remedy,\n );\n return normalized;\n }\n\n const handlers: RoomDriverHandlers = {\n participants(list) {\n const joinedAt = new Date(now()).toISOString();\n const before = new Set(store.snapshot().participants.map((p) => p.identity));\n store.setParticipants(list.map((entry) => projectParticipant(entry, joinedAt)));\n // 🚨 A HAND IS DATA-PLANE STATE, and the data plane has no history: a\n // person who joins after a hand went up would never see it, and the host\n // would call on people out of order. So each client RE-ANNOUNCES its own\n // raised hand, with its original time, when someone new arrives — the\n // queue position travels with it, and `store.setHand` keeps the first.\n const snapshot = store.snapshot();\n const newcomer = snapshot.participants.some(\n (participant) => !participant.isLocal && !before.has(participant.identity),\n );\n const me = snapshot.participants.find((p) => p.identity === snapshot.localIdentity);\n if (newcomer && before.size > 0 && me?.handRaised === true) {\n void publish(DATA_TOPICS.hand, { raised: true, raisedAt: me.handRaisedAt ?? now() }).catch(\n () => undefined,\n );\n }\n },\n roomMetadata(metadata) {\n // THE SERVER'S ROOM STATE (Meet wave 2). Only `UpdateRoomMetadata` writes\n // it, and only `services/meet/moderation.py` calls that. A malformed or\n // empty string means \"nothing set\", never a throw inside a room event.\n let spotlight: ParticipantIdentity | null = null;\n if (metadata.length > 0) {\n try {\n const parsed: unknown = JSON.parse(metadata);\n if (typeof parsed === \"object\" && parsed !== null) {\n const value = (parsed as { spotlight?: unknown }).spotlight;\n if (typeof value === \"string\" && value.length > 0) spotlight = asParticipantIdentity(value);\n }\n } catch {\n report(\n \"warn\",\n \"meet: the room's metadata is not JSON, so no spotlight was read from it\",\n \"Only aidream writes room metadata; check services/meet/moderation.py.\",\n );\n }\n }\n if (store.snapshot().spotlight !== spotlight) store.patch({ spotlight });\n },\n activeSpeakers(identities) {\n store.setSpeaking(identities.map(asParticipantIdentity));\n },\n quality(who, value) {\n store.setQuality(asParticipantIdentity(who), value);\n },\n connectionState(state) {\n // `reconnecting` is a VISIBLE state, not a silent one: a frozen tile with\n // no explanation is indistinguishable from a crashed app.\n if (state === \"connected\") store.patch({ phase: \"connected\", failure: null });\n else if (state === \"reconnecting\") store.patch({ phase: \"reconnecting\" });\n else if (state === \"connecting\") store.patch({ phase: \"connecting\" });\n },\n transcription(event) {\n // A CAPTION IS A HINT (D16). It is stored as one, next to the durable\n // rows, and the reconciliation in `transcript.ts` decides which of the two\n // a line ends up being. Nothing else in this package reads captions.\n const snapshot = store.snapshot();\n const meeting = snapshot.meeting;\n if (meeting === null) {\n // A caption with no meeting record has nothing durable to reconcile\n // against later. An ad-hoc call room is exactly that case; dropping it\n // is correct, and it is not silent — it is stated here.\n return;\n }\n // `lk.transcribed_participant_identity` is supplied by the publisher and\n // only says who they CLAIM to be transcribing. The stream's publisher is\n // the SFU-reported identity; captions are admitted only from this\n // meeting's deterministic note-taker. This remains display-only (D16),\n // but a room participant cannot write a fake line into the caption rail.\n // This check deliberately does not wait for a roster event: the first\n // note-taker utterance may arrive before its roster projection.\n if (event.publisherIdentity !== noteTakerIdentity(meeting.id)) {\n report(\n \"warn\",\n \"meet: ignored a caption from a participant that is not this meeting's note-taker\",\n \"Captions are accepted only from the server-dispatched note-taker; the durable transcript remains authoritative.\",\n );\n return;\n }\n const speakerIdentity = asParticipantIdentity(event.speakerIdentity);\n const speaker = snapshot.participants.find(\n (participant) => participant.identity === speakerIdentity,\n );\n store.ingestCaption(\n captionSegment({\n captionId: event.segmentId,\n meetingId: meeting.id,\n identity: speakerIdentity,\n // 🚨 ONE ANSWER TO \"WHO SAID THAT\" (MRI-A16). This line used to fall\n // back to `event.speakerIdentity` — the raw LiveKit token — which is\n // how a guest's caption rail read `guest:c8-spk-1` in the same second\n // the host's read \"Ada Lovelace\". The book keeps the last known name\n // for somebody who has left, and says \"Unnamed guest\" when nothing\n // anywhere has ever known one. It never prints a token.\n speaker: displayNameFor(snapshot.names, speakerIdentity, speaker?.displayName),\n text: event.text,\n final: event.final,\n startedAt: event.at,\n }),\n );\n },\n data(topic, payload, from) {\n // 🚨 THE SERVER'S OWN EVENTS COME FIRST, and they are the only live feed a\n // session-less guest has (MRI-A12). They are handled before the `mx.*`\n // control plane because they are a different KIND of message: published by\n // the platform with a `roomAdmin` grant no participant token can claim,\n // carrying durable rows rather than a sender's intent.\n if (isRoomEventTopic(topic)) {\n // `matrx.meet.*` is a server namespace, not an ACL. Any participant\n // may publish to a topic, including one with an agent-looking name;\n // only RoomService.SendData reaches the SDK without a participant.\n if (from !== null) {\n report(\n \"warn\",\n `meet: ignored participant-published server event on ${topic}`,\n \"Only aidream may publish matrx.meet.* events. The durable meeting record remains unchanged.\",\n );\n return;\n }\n let body: unknown;\n try {\n body = JSON.parse(payload);\n } catch {\n report(\n \"warn\",\n `meet: dropped an unparseable room event on ${topic}`,\n \"This topic is published by aidream only. Non-JSON here means a client is \" +\n \"publishing under the server's namespace, or the payload was truncated.\",\n );\n return;\n }\n if (topic === ROOM_EVENTS.ended && options.resolveMeeting !== undefined) {\n const meeting = store.snapshot().meeting;\n if (typeof body === \"object\" && body !== null && \"meeting_id\" in body && body.meeting_id === meeting?.id) {\n void confirmMeetingEnd();\n } else {\n report(\"warn\", \"Meet ignored an ending for another or missing meeting\", \"Only a matching canonical meeting can end this transport.\");\n }\n return;\n }\n const outcome = applyRoomEvent({ store, topic, payload: body, now });\n if (!outcome.handled) {\n // NEVER SILENT. A dropped room event is a note, a decision or an\n // ending that a guest will simply never see, and the reason has to be\n // reachable from the surface rather than from a debugger.\n report(\n \"warn\",\n `meet: ignored a room event on ${topic} — ${outcome.ignored ?? \"no reason given\"}`,\n \"The durable row still exists behind the meeting link. Signed-in members \" +\n \"receive it over Postgres Changes; a guest sees it on their next join.\",\n );\n }\n return;\n }\n let envelope: DataEnvelope = {};\n try {\n const parsed: unknown = JSON.parse(payload);\n if (typeof parsed === \"object\" && parsed !== null) envelope = parsed as DataEnvelope;\n } catch {\n report(\n \"warn\",\n `meet: dropped an unparseable data message on ${topic}`,\n \"A sender is publishing non-JSON on a reserved mx.* topic. Use publishData through \" +\n \"the engine so the envelope is always well formed.\",\n );\n return;\n }\n const sender = asParticipantIdentity(from ?? \"\");\n switch (topic) {\n case DATA_TOPICS.hand:\n store.setHand(\n sender,\n envelope.raised === true,\n typeof envelope.raisedAt === \"number\" ? envelope.raisedAt : now(),\n );\n return;\n case DATA_TOPICS.reaction:\n if (typeof envelope.emoji === \"string\") {\n store.addReaction({\n id: envelope.id ?? `${sender}-${now()}`,\n identity: sender,\n emoji: envelope.emoji,\n at: now(),\n });\n }\n return;\n case DATA_TOPICS.chat:\n // ONLY PRIVATE MESSAGES ride the data plane since 0.8: a message to\n // everyone is SAVED through the server and arrives as the server's\n // `matrx.meet.chat`. A participant's un-addressed `mx.chat` packet is\n // an older client's ephemeral chat — shown, never mistaken for saved.\n if (typeof envelope.text === \"string\") {\n const local = store.snapshot().localIdentity;\n store.addChat({\n id: envelope.id ?? `${sender}-${now()}`,\n identity: sender,\n displayName: envelope.name ?? sender,\n text: envelope.text,\n at: envelope.at ?? new Date(now()).toISOString(),\n ...(typeof envelope.to === \"string\" && local !== null ? { to: local } : {}),\n });\n }\n return;\n default:\n // Unknown topics are IGNORED, never thrown on — that is what lets a\n // newer client ship a new in-room feature without breaking old ones.\n return;\n }\n },\n disconnected(reason) {\n store.patch({ phase: \"left\" });\n options.onLeft?.(reason);\n },\n };\n\n async function connect(request: JoinRequest): Promise<void> {\n store.patch({ phase: \"requesting-token\", failure: null });\n const token = await tokens.get({\n roomName: request.roomName,\n identity,\n ...(request.meetingId !== undefined ? { meetingId: request.meetingId } : {}),\n ...(request.slug !== undefined ? { slug: request.slug } : {}),\n });\n current = token;\n // 🚨 THE GRANTS LAND WITH THE TOKEN, before any roster exists (MRI-A11).\n // Waiting for the LiveKit roster to learn that this person is the host means\n // the host's own controls flicker in — or, when a roster event arrives with\n // empty metadata, never appear at all. That was the shipped defect.\n store.patch({\n localIdentity: token.identity,\n grants: {\n role: token.role,\n canRecord: token.canRecord,\n canPublish: token.canPublish,\n canSubscribe: token.canSubscribe,\n },\n });\n\n // THE LOBBY IS A PHASE, NOT AN ERROR (D6). The server said \"wait\"; the UI\n // shows the waiting room and the room channel delivers the host's decision.\n if (token.lobby) {\n store.patch({ phase: \"lobby\" });\n return;\n }\n\n store.patch({ phase: \"connecting\" });\n const created = await options.driverFactory(handlers);\n if (disposed) {\n // Unmounted mid-connect. Disconnect the room we just built rather than\n // leaking it — this is the \"camera light stays on\" bug.\n await created.disconnect();\n return;\n }\n driver = created;\n await created.connect(token.serverUrl, token.token);\n\n // 🚨 IN THE ROOM. Attendance is settled HERE, before a single device is\n // touched. Everything below is best-effort publishing; nothing below can\n // unwind the join. See `attendance.ts` for the defect this closes.\n store.patch({ phase: \"connected\", failure: null });\n store.setLocalTrack(\"microphone\", IDLE_TRACK);\n store.setLocalTrack(\"camera\", IDLE_TRACK);\n\n // THE REMEMBERED CHOICES GO ON BEFORE ANY DEVICE DOES, so the first frame\n // anyone sees is already blurred and the first word already cleaned.\n const effects = options.effectsStorage?.load() ?? store.snapshot().effects;\n store.patch({ effects });\n // Only what DIFFERS from the browser default is applied on the way in: a\n // default join touches nothing it does not have to.\n if (!effects.noiseSuppression || effects.background !== \"none\") {\n try {\n await applyEffects(created, effects);\n } catch {\n // Reported inside; the join never depends on an effect.\n }\n }\n for (const kind of [\"audioinput\", \"videoinput\", \"audiooutput\"] as const) {\n const chosen = options.resolveDevice?.(kind) ?? null;\n if (chosen === null || chosen === \"default\") continue;\n try {\n await created.switchDevice(kind, chosen);\n } catch (error) {\n const normalized = normalizeDeviceError(error, `meet.switchDevice(${kind})`);\n report(\"warn\", normalized.message, normalized.remedy);\n }\n }\n\n if (request.mode === \"video\") {\n await enableTrack(created, \"camera\", true);\n }\n if (request.microphone !== false) {\n await enableTrack(created, \"microphone\", true);\n }\n }\n\n /**\n * THE ONE PATH that turns a local device on or off — used by the join and by\n * the in-room controls alike, so \"enable it later\" cannot behave differently\n * from \"enable it on the way in\". A refusal is recorded as state with the\n * browser's own reason and a remedy, reported as a diagnostic, and returned;\n * it is never thrown, because there is no caller for whom losing the room is\n * the right answer to a busy microphone.\n */\n async function enableTrack(\n target: MeetRoomDriver,\n kind: \"microphone\" | \"camera\",\n enabled: boolean,\n ): Promise<LocalTrackState> {\n try {\n if (kind === \"microphone\") await target.setMicrophoneEnabled(enabled);\n else await target.setCameraEnabled(enabled);\n const state: LocalTrackState = { enabled, unavailable: null };\n store.setLocalTrack(kind, state);\n return state;\n } catch (error) {\n const normalized = normalizeDeviceError(error, `meet.${kind}`);\n const state: LocalTrackState = { enabled: false, unavailable: unavailableFrom(normalized) };\n store.setLocalTrack(kind, state);\n report(\"warn\", normalized.message, normalized.remedy);\n return state;\n }\n }\n\n async function publish(\n topic: string,\n body: Record<string, unknown>,\n to?: readonly string[],\n ): Promise<void> {\n if (driver === null) return;\n await driver.publishData(topic, JSON.stringify(body), to);\n }\n\n async function applyEffects(target: MeetRoomDriver, effects: MediaEffects): Promise<void> {\n try {\n await target.setAudioProcessing?.({\n noiseSuppression: effects.noiseSuppression,\n echoCancellation: true,\n autoGainControl: true,\n });\n } catch (error) {\n report(\"warn\", `meet: noise suppression could not be applied: ${String(error)}`, \"The microphone keeps working without it.\");\n }\n if (target.setVideoEffect === undefined) return;\n const effect: VideoEffect =\n effects.background === \"blur\"\n ? { kind: \"blur\" }\n : effects.background === \"image\" && effects.backgroundImage !== null\n ? { kind: \"image\", imageUrl: effects.backgroundImage }\n : { kind: \"none\" };\n if (effect.kind !== \"none\" && target.supportsVideoEffects?.() === false) return;\n try {\n await target.setVideoEffect(effect);\n } catch (error) {\n const normalized = normalizeMeetError(error, \"meet.setVideoEffect\");\n report(\"warn\", normalized.message, normalized.remedy);\n throw normalized;\n }\n }\n\n return {\n join(request) {\n // SINGLE FLIGHT: a strict-mode double effect and a user's second click\n // share one join. Two joins for one identity make LiveKit drop the first.\n if (joining !== null) return joining;\n lastRequest = request;\n joining = connect(request)\n .catch((error: unknown) => {\n throw fail(error, \"meet.join\");\n })\n .finally(() => {\n joining = null;\n });\n return joining;\n },\n async rejoin() {\n const request = lastRequest;\n if (request === null) {\n // Nothing to rejoin is not an error and never a silent no-op: it means\n // this engine never joined, which a caller can only reach by wiring the\n // admission signal to a room nobody is waiting in.\n report(\n \"warn\",\n \"meet.rejoin: this room engine has never joined, so there is nothing to rejoin\",\n \"Call join() first. An admission verdict for a participant who never knocked is \" +\n \"ignored rather than minting a token nobody asked for.\",\n );\n return;\n }\n if (joining !== null) return joining;\n // THE LOBBY TOKEN IS THROWN AWAY. It grants neither publish nor\n // subscribe; reusing it would put the admitted guest in the room as a\n // participant who can neither speak nor hear.\n tokens.invalidate(request.roomName);\n current = null;\n joining = connect(request)\n .catch((error: unknown) => {\n throw fail(error, \"meet.rejoin\");\n })\n .finally(() => {\n joining = null;\n });\n return joining;\n },\n leave: leaveRoom,\n // Turning a device on mid-meeting is the SAME operation as turning it on\n // during the join, so it runs the same function. A failure here used to\n // stamp the room `failed` — a busy microphone would blank a live meeting.\n async setMicrophoneEnabled(enabled) {\n if (driver === null) return;\n await enableTrack(driver, \"microphone\", enabled);\n },\n async setCameraEnabled(enabled) {\n if (driver === null) return;\n await enableTrack(driver, \"camera\", enabled);\n },\n async setScreenShareEnabled(enabled) {\n if (driver === null) return;\n try {\n await driver.setScreenShareEnabled(enabled);\n } catch (error) {\n throw fail(error, \"meet.setScreenShareEnabled\");\n }\n },\n async raiseHand(raised) {\n const local = store.snapshot().localIdentity;\n // Applied LOCALLY FIRST. A hand that only rises when the round trip\n // returns feels broken, and the data plane is reliable-ordered anyway.\n if (local !== null) store.setHand(local, raised);\n await publish(DATA_TOPICS.hand, { raised, raisedAt: now() });\n },\n async react(emoji) {\n const local = store.snapshot().localIdentity;\n const id = `${local ?? \"local\"}-${now()}`;\n if (local !== null) {\n store.addReaction({ id, identity: local, emoji, at: now() });\n }\n await publish(DATA_TOPICS.reaction, { id, emoji });\n },\n async sendPrivateChat(to, text) {\n const trimmed = text.trim();\n if (trimmed.length === 0) return;\n const local = store.snapshot().localIdentity;\n const id = `${local ?? \"local\"}-${now()}`;\n const at = new Date(now()).toISOString();\n if (local !== null) {\n store.addChat({ id, identity: local, displayName: identity.displayName, text: trimmed, at, to });\n }\n await publish(\n DATA_TOPICS.chat,\n { id, text: trimmed, at, name: identity.displayName, to },\n [to],\n );\n },\n async setEffects(next) {\n const previous = store.snapshot().effects;\n const merged: MediaEffects = { ...previous, ...next };\n store.patch({ effects: merged });\n options.effectsStorage?.save(merged);\n if (driver === null) return;\n try {\n await applyEffects(driver, merged);\n } catch {\n // The camera keeps running without the effect; the choice reverts so\n // the control never claims an effect that is not on screen.\n const reverted: MediaEffects = { ...merged, background: previous.background, backgroundImage: previous.backgroundImage };\n store.patch({ effects: reverted });\n options.effectsStorage?.save(reverted);\n }\n },\n supportsVideoEffects() {\n return driver?.supportsVideoEffects?.() ?? false;\n },\n async switchDevice(kind, deviceId) {\n if (driver === null) return;\n await driver.switchDevice(kind, deviceId);\n },\n pin(who) {\n store.patch({ pinned: who, layout: who === null ? \"grid\" : \"speaker\" });\n },\n setLayout(layout) {\n store.patch({ layout });\n },\n attach(who, kind, element) {\n if (driver === null) return () => undefined;\n return driver.attach(who, kind, element);\n },\n token: () => current,\n async dispose() {\n disposed = true;\n if (driver !== null) {\n const target = driver;\n driver = null;\n await target.disconnect();\n }\n store.reset();\n },\n };\n}\n\n/** Exported for the host-power check in UI code — one definition, one rank. */\nexport function canModerate(participant: MeetParticipant | undefined): boolean {\n return participant !== undefined && isHostRole(participant.role);\n}\n\nexport function hostUserIds(participants: readonly MeetParticipant[]): readonly UserId[] {\n return participants\n .filter((participant) => participant.role === \"host\" && participant.userId !== null)\n .map((participant) => participant.userId as UserId);\n}\n","/**\n * A PARTICIPANT'S OWN MEDIA CHOICES, REMEMBERED (Meet wave 2).\n *\n * Noise suppression and the camera background are personal and per device —\n * Zoom and Meet both remember them — so they live in this browser, never on a\n * server. Blocked storage means the defaults (suppression on, no background),\n * never a failed join.\n */\n\nimport type { EffectsStorage } from \"./room\";\nimport { DEFAULT_EFFECTS, type MediaEffects } from \"./store\";\n\nfunction coerce(value: unknown): MediaEffects {\n if (typeof value !== \"object\" || value === null) return DEFAULT_EFFECTS;\n const row = value as Record<string, unknown>;\n const background =\n row[\"background\"] === \"blur\" || row[\"background\"] === \"image\" ? row[\"background\"] : \"none\";\n const backgroundImage = typeof row[\"backgroundImage\"] === \"string\" ? row[\"backgroundImage\"] : null;\n return {\n noiseSuppression: row[\"noiseSuppression\"] !== false,\n background: background === \"image\" && backgroundImage === null ? \"none\" : background,\n backgroundImage,\n };\n}\n\nexport function createWebEffectsStorage(key = \"mx.meet.effects\"): EffectsStorage {\n let memory: MediaEffects = DEFAULT_EFFECTS;\n const storage = (globalThis as { localStorage?: Storage }).localStorage;\n return {\n load() {\n if (storage === undefined) return memory;\n try {\n const raw = storage.getItem(key);\n return raw === null ? memory : coerce(JSON.parse(raw));\n } catch {\n return memory;\n }\n },\n save(effects) {\n memory = effects;\n try {\n storage?.setItem(key, JSON.stringify(effects));\n } catch {\n // Storage blocked: the choice lasts for this visit.\n }\n },\n };\n}\n","/**\n * THE IN-ROOM SERVER CALLS (Meet wave 2) — host moderation and the SAVED chat.\n *\n * 🚨 **Why these are server calls and not data packets.** Through 0.7.x a host's\n * \"Mute\" and \"Remove\" were published on the room's data plane (`mx.host`) and\n * nothing anywhere listened: the buttons did nothing. A client cannot be the\n * authority on host power, and a guest cannot write the database. So both go to\n * aidream (`POST /v1/meet/moderate`, `POST|GET /v1/meet/chat`), which decides the\n * actor's role from the meeting itself, performs the act through LiveKit's server\n * API, writes what is durable, and tells the room on its own `matrx.meet.*` topic.\n *\n * A guest proves who they are with the room pass this server signed for them, in\n * `x-meet-room-token` — a header, never a URL.\n */\n\nimport { readServerRefusal } from \"./ai\";\nimport type { MeetApi } from \"./api\";\nimport { MeetError } from \"./errors\";\nimport { chatFromRow } from \"./room-events\";\nimport type { MeetStore, RoomChatMessage } from \"./store\";\nimport { MEET_ROUTES, ROOM_TOKEN_HEADER } from \"./tokens\";\nimport type { ParticipantIdentity } from \"./types\";\n\n/** Every host power the server performs. One vocabulary with `services/meet/moderation.py`. */\nexport type ModerationAction =\n | \"mute\"\n | \"stop_video\"\n | \"stop_screen\"\n | \"mute_all\"\n | \"ask_unmute\"\n | \"ask_all_unmute\"\n | \"spotlight\"\n | \"lower_hand\"\n | \"lower_all_hands\"\n | \"make_cohost\"\n | \"revoke_cohost\"\n | \"transfer_host\"\n | \"rename\"\n | \"remove\"\n | \"report\";\n\nexport const MODERATION_ACTIONS: readonly ModerationAction[] = [\n \"mute\",\n \"stop_video\",\n \"stop_screen\",\n \"mute_all\",\n \"ask_unmute\",\n \"ask_all_unmute\",\n \"spotlight\",\n \"lower_hand\",\n \"lower_all_hands\",\n \"make_cohost\",\n \"revoke_cohost\",\n \"transfer_host\",\n \"rename\",\n \"remove\",\n \"report\",\n];\n\nexport interface ModerationRequest {\n readonly action: ModerationAction;\n readonly identity?: ParticipantIdentity | null | undefined;\n readonly name?: string | undefined;\n readonly reason?: string | undefined;\n}\n\nexport interface ModerationResult {\n readonly action: ModerationAction;\n readonly affected: readonly string[];\n /** The server's sentence for the actor. */\n readonly message: string;\n}\n\nexport interface InRoomClient {\n moderate(request: ModerationRequest): Promise<ModerationResult>;\n /** Send a message to EVERYONE. Saved; shows at once as pending, then as saved. */\n sendChat(text: string): Promise<void>;\n /** Read the saved chat once per join, so a late joiner sees what was said. */\n loadChat(): Promise<void>;\n}\n\nexport interface InRoomClientOptions {\n api: MeetApi;\n store: MeetStore;\n /** The room pass for THIS meeting, or null (a signed-in member needs none). */\n resolveRoomToken: () => string | null;\n now?: (() => number) | undefined;\n}\n\nexport function createInRoomClient(options: InRoomClientOptions): InRoomClient {\n const { api, store } = options;\n const now = options.now ?? (() => Date.now());\n\n function meetingId(operation: string): string {\n const meeting = store.snapshot().meeting;\n if (meeting === null) {\n throw new MeetError(\n \"not-found\",\n `${operation}: this room has no meeting record`,\n \"Moderation and saved chat belong to a meeting. An ad-hoc call has neither.\",\n );\n }\n return meeting.id;\n }\n\n function headers(): Record<string, string> | undefined {\n const token = options.resolveRoomToken();\n return token === null ? undefined : { [ROOM_TOKEN_HEADER]: token };\n }\n\n async function refusal(response: Response, operation: string, remedy: string): Promise<MeetError> {\n let body: unknown = null;\n try {\n body = await response.json();\n } catch {\n body = null;\n }\n const said = readServerRefusal(body);\n return new MeetError(\n response.status === 403 || response.status === 401\n ? \"forbidden\"\n : response.status === 404\n ? \"not-found\"\n : response.status === 409\n ? \"conflict\"\n : \"transport\",\n said?.reason ?? `${operation}: the server answered ${response.status}`,\n said?.remedy !== undefined && said.remedy.length > 0 ? said.remedy : remedy,\n );\n }\n\n return {\n async moderate(request) {\n const operation = `meet.moderate(${request.action})`;\n const hdrs = headers();\n const response = await api.request({\n path: MEET_ROUTES.moderate,\n method: \"POST\",\n operation,\n body: {\n meeting_id: meetingId(operation),\n action: request.action,\n ...(request.identity != null ? { identity: request.identity } : {}),\n ...(request.name !== undefined ? { name: request.name } : {}),\n ...(request.reason !== undefined ? { reason: request.reason } : {}),\n },\n ...(hdrs !== undefined ? { headers: hdrs } : {}),\n });\n if (!response.ok) {\n throw await refusal(\n response,\n operation,\n \"Nothing was changed. The server decides host powers from the meeting itself.\",\n );\n }\n const payload = (await response.json()) as Record<string, unknown>;\n return {\n action: request.action,\n affected: Array.isArray(payload[\"affected\"])\n ? payload[\"affected\"].filter((value): value is string => typeof value === \"string\")\n : [],\n message: typeof payload[\"message\"] === \"string\" ? payload[\"message\"] : \"Done.\",\n };\n },\n\n async sendChat(text) {\n const body = text.trim();\n if (body.length === 0) return;\n const operation = \"meet.sendChat\";\n const id = meetingId(operation);\n const snapshot = store.snapshot();\n const me = snapshot.participants.find((p) => p.identity === snapshot.localIdentity);\n // PENDING AT ONCE: a message that appears only after a round trip feels\n // broken. It is marked pending (not `saved`) until the server's row lands.\n const localId = `pending-${now()}`;\n const pending: RoomChatMessage = {\n id: localId,\n identity: snapshot.localIdentity ?? (\"local\" as ParticipantIdentity),\n displayName: me?.displayName ?? \"You\",\n text: body,\n at: new Date(now()).toISOString(),\n saved: false,\n };\n store.addChat(pending);\n const hdrs = headers();\n let response: Response;\n try {\n response = await api.request({\n path: MEET_ROUTES.chat,\n method: \"POST\",\n operation,\n body: { meeting_id: id, body },\n ...(hdrs !== undefined ? { headers: hdrs } : {}),\n });\n } catch (error) {\n store.settleChat(localId, { failed: \"Not sent — the server could not be reached.\" });\n throw error;\n }\n if (!response.ok) {\n const error = await refusal(response, operation, \"Your message was not sent.\");\n store.settleChat(localId, { failed: error.message });\n throw error;\n }\n const saved = chatFromRow((await response.json()) as Record<string, unknown>);\n if (saved === null) {\n store.settleChat(localId, { failed: \"The server's answer could not be read.\" });\n return;\n }\n store.settleChat(localId, saved);\n },\n\n async loadChat() {\n const operation = \"meet.loadChat\";\n const id = meetingId(operation);\n const hdrs = headers();\n const response = await api.request({\n path: `${MEET_ROUTES.chat}?meeting_id=${encodeURIComponent(id)}`,\n method: \"GET\",\n operation,\n ...(hdrs !== undefined ? { headers: hdrs } : {}),\n });\n if (!response.ok) {\n throw await refusal(\n response,\n operation,\n \"Messages sent before you joined could not be read. New messages still arrive.\",\n );\n }\n const payload = (await response.json()) as { messages?: unknown };\n const rows = Array.isArray(payload.messages) ? payload.messages : [];\n const messages = rows\n .map((row) =>\n typeof row === \"object\" && row !== null ? chatFromRow(row as Record<string, unknown>) : null,\n )\n .filter((message): message is RoomChatMessage => message !== null);\n store.loadChat(messages);\n },\n };\n}\n","/**\n * THE ONE PLACE `livekit-client` IS TOUCHED.\n *\n * Everything above this file talks to `MeetRoomDriver`. That containment is\n * what lets the engine's whole behavior — ring timeouts, admission, escalation,\n * reconnection — be proven in a node test, and it is why an SDK upgrade is a\n * single-file review rather than a package-wide audit.\n *\n * 🚨 **THE IMPORT IS DYNAMIC, DELIBERATELY.** `import type` is erased, and the\n * runtime `await import(\"livekit-client\")` happens inside `connect()`. So:\n * importing `@ai-matrx/meet` during SSR, or on a page that renders a call\n * BUTTON but never a call, pulls in none of the media SDK and touches no\n * browser API (independence contract §4). A static import here would put ~400KB\n * of WebRTC into every consumer's first load and break RSC rendering.\n *\n * The mapping helpers below are exported for their own tests: an SDK enum\n * renamed upstream must fail a named test, not silently become \"unknown\" on\n * every tile.\n */\n\nimport type {\n ConnectionQuality as LiveKitQuality,\n Participant,\n Room,\n RoomOptions,\n} from \"livekit-client\";\nimport { MeetError, normalizeDeviceError } from \"./errors\";\nimport {\n TRANSCRIPTION_ATTRIBUTES,\n TRANSCRIPTION_TOPIC,\n type AudioProcessing,\n type DriverConnectionState,\n type DriverParticipant,\n type DriverTrackKind,\n type MeetRoomDriver,\n type RoomDriverHandlers,\n type VideoEffect,\n} from \"./room-driver\";\nimport type { ConnectionQuality } from \"./types\";\n\n/**\n * LiveKit's quality enum → ours. Mapped explicitly rather than cast: the SDK\n * has five states and our UI has five sentences, and an unmapped one must\n * degrade to `unknown` (an honest \"we don't know\") rather than to `excellent`\n * (a lie that hides a failing call).\n */\nexport function mapQuality(quality: LiveKitQuality | string): ConnectionQuality {\n switch (quality) {\n case \"excellent\":\n return \"excellent\";\n case \"good\":\n return \"good\";\n case \"poor\":\n return \"poor\";\n case \"lost\":\n return \"lost\";\n default:\n return \"unknown\";\n }\n}\n\nexport function mapConnectionState(state: string): DriverConnectionState {\n switch (state) {\n case \"connected\":\n return \"connected\";\n case \"connecting\":\n return \"connecting\";\n case \"reconnecting\":\n case \"signalReconnecting\":\n return \"reconnecting\";\n default:\n return \"disconnected\";\n }\n}\n\n/**\n * A LiveKit participant → our snapshot.\n *\n * 🚨 `name` IS REPORTED EXACTLY AS LIVEKIT GAVE IT, empty string and all\n * (MRI-A18). Through 0.4.12 it fell back to the identity here, which meant a\n * driver — the thing furthest from any screen — invented a \"name\" that\n * `core/names.ts` then had to recognize and refuse. A driver reports; it does\n * not name. The one fallback lives in `projectParticipant`, and it is the name\n * book's honest placeholder rather than a token.\n */\nexport function snapshotParticipant(\n participant: Pick<\n Participant,\n \"identity\" | \"name\" | \"metadata\" | \"isMicrophoneEnabled\" | \"isCameraEnabled\" | \"isScreenShareEnabled\"\n > & { attributes?: Readonly<Record<string, string>> | undefined },\n isLocal: boolean,\n): DriverParticipant {\n const name = participant.name;\n return {\n identity: participant.identity,\n name: name ?? \"\",\n metadata: participant.metadata ?? null,\n // ATTRIBUTES ARE PART OF THE SNAPSHOT, not read ad hoc later: the note-taker\n // announces the consent notice here (D10) and the roster is the only place\n // this package looks at a participant.\n attributes: participant.attributes ?? {},\n isLocal,\n micEnabled: participant.isMicrophoneEnabled,\n cameraEnabled: participant.isCameraEnabled,\n screenSharing: participant.isScreenShareEnabled,\n };\n}\n\nexport interface LiveKitDriverOptions {\n /** Adaptive stream + dynacast default ON — R5 scale honesty, not a knob. */\n roomOptions?: RoomOptions | undefined;\n}\n\n/** The browser defaults every call product ships with. */\nexport const DEFAULT_AUDIO_PROCESSING: AudioProcessing = {\n noiseSuppression: true,\n echoCancellation: true,\n autoGainControl: true,\n};\n\n/**\n * Background effects run a segmentation model on the GPU (MediaPipe via\n * `@livekit/track-processors`). A browser without `OffscreenCanvas` or WebGL2\n * cannot — the control is then ABSENT, never a toggle that silently fails.\n */\nexport function videoEffectsSupported(): boolean {\n const scope = globalThis as unknown as {\n OffscreenCanvas?: unknown;\n document?: { createElement(tag: string): { getContext(kind: string): unknown } };\n };\n if (typeof scope.OffscreenCanvas === \"undefined\" || scope.document === undefined) return false;\n try {\n return scope.document.createElement(\"canvas\").getContext(\"webgl2\") !== null;\n } catch {\n return false;\n }\n}\n\n/**\n * Put the chosen effect on the local camera. The processor package is imported\n * lazily, exactly like `livekit-client` itself, so a meeting nobody blurs never\n * downloads a segmentation model.\n */\nasync function applyVideoEffect(target: Room, effect: VideoEffect): Promise<void> {\n const { Track } = await import(\"livekit-client\");\n const track = target.localParticipant.getTrackPublication(Track.Source.Camera)?.track as\n | {\n setProcessor(processor: unknown): Promise<void>;\n stopProcessor(): Promise<void>;\n }\n | undefined;\n if (track === undefined) return; // camera off: applied when it turns on.\n try {\n if (effect.kind === \"none\") {\n await track.stopProcessor();\n return;\n }\n const processors = await import(\"@livekit/track-processors\");\n const processor =\n effect.kind === \"blur\"\n ? processors.BackgroundBlur(effect.radius ?? 12)\n : processors.VirtualBackground(effect.imageUrl);\n await track.setProcessor(processor);\n } catch (error) {\n throw new MeetError(\n \"media-unsupported\",\n \"The background effect could not start on this camera\",\n \"Background effects need a browser with WebGL2 (current Chrome, Edge, Firefox or Safari). \" +\n \"Your video continues without the effect.\",\n error,\n );\n }\n}\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\nexport function createLiveKitDriver(\n handlers: RoomDriverHandlers,\n options: LiveKitDriverOptions = {},\n): MeetRoomDriver {\n let room: Room | null = null;\n /**\n * The roster projection for the CURRENT room, kept out here so `connect()`\n * can fire it once the transport is up. See the call site for why.\n */\n let projectRoster: (() => void) | null = null;\n /** What the person chose, kept so a re-enabled track gets it too. */\n let audioCapture: AudioProcessing = DEFAULT_AUDIO_PROCESSING;\n let videoEffect: VideoEffect = { kind: \"none\" };\n\n async function load(): Promise<Room> {\n if (room !== null) return room;\n let module: typeof import(\"livekit-client\");\n try {\n module = await import(\"livekit-client\");\n } catch (error) {\n throw new MeetError(\n \"misconfigured\",\n \"livekit-client could not be loaded\",\n \"`livekit-client` is a dependency of @ai-matrx/meet and is imported lazily at \" +\n \"connect time. If this failed, the bundler excluded it — remove it from any \" +\n \"`external`/`serverExternalPackages` list, or pass your own driver factory.\",\n error,\n );\n }\n const { Room: LiveKitRoom, RoomEvent, Track } = module;\n const created = new LiveKitRoom({\n // R5: large meetings degrade gracefully instead of melting a laptop.\n adaptiveStream: true,\n dynacast: true,\n ...options.roomOptions,\n });\n\n const roster = (): void => {\n const local = snapshotParticipant(created.localParticipant, true);\n const remotes = [...created.remoteParticipants.values()].map((participant) =>\n snapshotParticipant(participant, false),\n );\n // The FULL roster every time. Every one of these six events changes what\n // a tile must render, and a delta protocol across six sources drifts.\n handlers.participants([local, ...remotes]);\n };\n\n projectRoster = roster;\n\n created\n .on(RoomEvent.ParticipantConnected, roster)\n .on(RoomEvent.ParticipantDisconnected, roster)\n .on(RoomEvent.TrackSubscribed, roster)\n .on(RoomEvent.TrackUnsubscribed, roster)\n .on(RoomEvent.TrackMuted, roster)\n .on(RoomEvent.TrackUnmuted, roster)\n .on(RoomEvent.LocalTrackPublished, roster)\n .on(RoomEvent.LocalTrackUnpublished, roster)\n // A SERVER DECISION CHANGED MID-MEETING (Meet wave 2): a co-host made or\n // unmade, the host handed over, a rename. The server re-stamps the\n // roster through `UpdateParticipant`; these three events carry it here.\n .on(RoomEvent.ParticipantNameChanged, roster)\n .on(RoomEvent.ParticipantAttributesChanged, roster)\n .on(RoomEvent.ParticipantMetadataChanged, roster)\n .on(RoomEvent.RoomMetadataChanged, (metadata) => {\n handlers.roomMetadata?.(metadata ?? \"\");\n })\n .on(RoomEvent.ActiveSpeakersChanged, (speakers) => {\n handlers.activeSpeakers(speakers.map((speaker) => speaker.identity));\n })\n .on(RoomEvent.ConnectionQualityChanged, (quality, participant) => {\n handlers.quality(participant.identity, mapQuality(quality));\n })\n .on(RoomEvent.ConnectionStateChanged, (state) => {\n handlers.connectionState(mapConnectionState(state));\n })\n .on(RoomEvent.DataReceived, (payload, participant, _kind, topic) => {\n handlers.data(\n topic ?? \"\",\n decoder.decode(payload),\n participant?.identity ?? null,\n );\n })\n .on(RoomEvent.Disconnected, (reason) => {\n handlers.disconnected(reason === undefined ? null : String(reason));\n });\n\n // LIVE CAPTIONS (D16). The agent publishes one text stream per utterance on\n // `lk.transcription`, re-sending the same `lk.segment_id` as the words firm\n // up, and the FINAL flag says which one is the last. The chunks are read as\n // they arrive — waiting for `readAll()` would make captions appear only\n // once the sentence was over, which is not a caption.\n //\n // 🚨 REGISTERED BEFORE `connect()`, deliberately: LiveKit buffers data\n // packets that arrive before the room is connected and replays them, but a\n // handler registered after the first stream header lands misses that\n // utterance outright — the first thing anyone says in the meeting.\n try {\n created.registerTextStreamHandler(TRANSCRIPTION_TOPIC, (reader, participantInfo) => {\n const attributes: Record<string, string> = { ...(reader.info.attributes ?? {}) };\n const segmentId =\n attributes[TRANSCRIPTION_ATTRIBUTES.segmentId] ?? reader.info.id;\n const trackId = attributes[TRANSCRIPTION_ATTRIBUTES.trackId] ?? null;\n const final = attributes[TRANSCRIPTION_ATTRIBUTES.final] === \"true\";\n // `lk.transcribed_participant_identity` is WHO IS BEING TRANSCRIBED.\n // The SFU's publisher identity stays the note-taker, so using it here\n // would attribute the whole meeting to the agent. Do not use the\n // sender-identity override: LiveKit accepts it from an agent publisher,\n // but aidream deliberately does not set it.\n const speakerIdentity =\n attributes[TRANSCRIPTION_ATTRIBUTES.speakerIdentity] ?? participantInfo.identity;\n const at = new Date(reader.info.timestamp || Date.now()).toISOString();\n void (async () => {\n let text = \"\";\n try {\n for await (const chunk of reader) {\n text += chunk;\n // Emit as it grows: a caption that only appears when the sentence\n // ends is a transcript, not a caption.\n handlers.transcription({\n segmentId,\n speakerIdentity,\n publisherIdentity: participantInfo.identity,\n text,\n final,\n trackId,\n at,\n });\n }\n } catch (error) {\n // A caption stream that dies is a caption we do not have. It is\n // never fatal to the meeting and never silent.\n handlers.data(\n TRANSCRIPTION_TOPIC,\n JSON.stringify({ error: String((error as Error)?.message ?? error) }),\n participantInfo.identity,\n );\n }\n })();\n });\n } catch {\n // Registering twice throws in the SDK. `load()` is single-flight through\n // `room`, so this can only happen on a re-entrant remount — in which case\n // the existing handler is already delivering captions.\n }\n\n // Kept for `attach`, which needs the SDK's Source enum at call time.\n sources = {\n camera: Track.Source.Camera,\n microphone: Track.Source.Microphone,\n screen: Track.Source.ScreenShare,\n };\n room = created;\n return created;\n }\n\n let sources: Record<DriverTrackKind, string> | null = null;\n\n function requireRoom(operation: string): Room {\n if (room === null) {\n throw new MeetError(\n \"transport\",\n `${operation}: the room is not connected`,\n \"Call connect() first. The engine never reaches this — it gates every media call \" +\n \"on its own phase — so seeing it means a consumer drove the driver directly.\",\n );\n }\n return room;\n }\n\n return {\n async connect(serverUrl, token) {\n const target = await load();\n try {\n await target.connect(serverUrl, token);\n } catch (error) {\n // A connect failure is either media permission (user-actionable) or\n // transport. Both must reach the UI with a sentence, never a spinner.\n throw normalizeDeviceError(error, \"meet.connect\");\n }\n // 🚨 PROJECT THE ROSTER ONCE, HERE. Every other roster source is an\n // EVENT, and a participant who publishes nothing into an empty room\n // generates none of them: no `LocalTrackPublished`, no\n // `ParticipantConnected`, no track events. Until 0.3.2 the join always\n // published a microphone, so `LocalTrackPublished` fired and hid this —\n // and the moment listen-only attendance became possible, a listen-only\n // host was absent from their own People panel, had no tile, and got NO\n // host controls at all (the note-taker could not be started), because\n // host powers are read off the local participant's roster entry.\n projectRoster?.();\n // The room's metadata arrives WITH the join (the spotlight lives there),\n // and `RoomMetadataChanged` fires only for later changes.\n handlers.roomMetadata?.(target.metadata ?? \"\");\n },\n async disconnect() {\n if (room === null) return;\n const target = room;\n room = null;\n try {\n target.unregisterTextStreamHandler(TRANSCRIPTION_TOPIC);\n } catch {\n // Already gone. Teardown is idempotent by contract.\n }\n projectRoster = null;\n await target.disconnect();\n },\n async setMicrophoneEnabled(enabled) {\n try {\n await requireRoom(\"setMicrophoneEnabled\").localParticipant.setMicrophoneEnabled(\n enabled,\n audioCapture,\n );\n } catch (error) {\n throw normalizeDeviceError(error, \"meet.setMicrophoneEnabled\");\n }\n },\n async setCameraEnabled(enabled) {\n try {\n const target = requireRoom(\"setCameraEnabled\");\n await target.localParticipant.setCameraEnabled(enabled);\n // A REMEMBERED EFFECT FOLLOWS THE CAMERA. Turning the camera back on must\n // not quietly show the room behind someone who chose to blur it.\n if (enabled && videoEffect.kind !== \"none\") await applyVideoEffect(target, videoEffect);\n } catch (error) {\n throw normalizeDeviceError(error, \"meet.setCameraEnabled\");\n }\n },\n async setScreenShareEnabled(enabled) {\n try {\n await requireRoom(\"setScreenShareEnabled\").localParticipant.setScreenShareEnabled(enabled);\n } catch (error) {\n throw normalizeDeviceError(error, \"meet.setScreenShareEnabled\");\n }\n },\n async publishData(topic, payload, to) {\n await requireRoom(\"publishData\").localParticipant.publishData(\n // `reliable` is not optional for a control plane: a dropped\n // \"hand lowered\" leaves a hand up on every other screen forever.\n encoder.encode(payload) as Uint8Array<ArrayBuffer>,\n to === undefined || to.length === 0\n ? { reliable: true, topic }\n : { reliable: true, topic, destinationIdentities: [...to] },\n );\n },\n async setAudioProcessing(processing) {\n audioCapture = { ...audioCapture, ...processing };\n const target = room;\n if (target === null) return;\n const { Track } = await import(\"livekit-client\");\n const publication = target.localParticipant.getTrackPublication(Track.Source.Microphone);\n const track = publication?.track;\n if (track === undefined || publication?.isMuted === true) return;\n try {\n // The browser's own processing, applied to the LIVE track: a restart\n // with new constraints, the same device, no renegotiation.\n await (track as unknown as { restartTrack(options: object): Promise<void> }).restartTrack({\n ...audioCapture,\n ...(target.getActiveDevice(\"audioinput\") !== undefined\n ? { deviceId: target.getActiveDevice(\"audioinput\") }\n : {}),\n });\n } catch (error) {\n throw normalizeDeviceError(error, \"meet.setAudioProcessing\");\n }\n },\n async setVideoEffect(effect) {\n videoEffect = effect;\n const target = room;\n if (target === null) return;\n await applyVideoEffect(target, effect);\n },\n supportsVideoEffects() {\n return videoEffectsSupported();\n },\n attach(identity, kind, element) {\n const target = requireRoom(\"attach\");\n const source = sources?.[kind];\n const participant =\n target.localParticipant.identity === identity\n ? target.localParticipant\n : target.remoteParticipants.get(identity);\n if (participant === undefined || source === undefined) return () => undefined;\n const publication = participant.getTrackPublication(source as never);\n const track = publication?.track;\n if (track === undefined) return () => undefined;\n track.attach(element);\n // The DETACH IS THE RETURN VALUE — a React effect's cleanup cannot forget\n // to call something it was handed.\n return () => {\n track.detach(element);\n };\n },\n activeDevices() {\n const target = room;\n if (target === null) {\n return { audioinput: null, videoinput: null, audiooutput: null };\n }\n return {\n audioinput: target.getActiveDevice(\"audioinput\") ?? null,\n videoinput: target.getActiveDevice(\"videoinput\") ?? null,\n audiooutput: target.getActiveDevice(\"audiooutput\") ?? null,\n };\n },\n async switchDevice(kind, deviceId) {\n try {\n await requireRoom(\"switchDevice\").switchActiveDevice(kind, deviceId);\n } catch (error) {\n throw normalizeDeviceError(error, \"meet.switchDevice\");\n }\n },\n };\n}\n\n/**\n * THE PRE-JOIN CAMERA PREVIEW (Meet wave 2) — the same SDK track and the same\n * background processor the room will use, so what someone sees before joining\n * is exactly what the meeting will see. Lives here because this file is the one\n * place `livekit-client` is touched.\n */\nexport interface CameraPreview {\n attach(element: HTMLVideoElement): void;\n setEffect(effect: VideoEffect): Promise<void>;\n stop(): void;\n}\n\nexport async function createCameraPreview(\n deviceId: string | null,\n effect: VideoEffect,\n): Promise<CameraPreview> {\n let module: typeof import(\"livekit-client\");\n try {\n module = await import(\"livekit-client\");\n } catch (error) {\n throw new MeetError(\n \"misconfigured\",\n \"livekit-client could not be loaded for the camera preview\",\n \"The bundler excluded `livekit-client`; remove it from any `external` list.\",\n error,\n );\n }\n let track: Awaited<ReturnType<typeof module.createLocalVideoTrack>>;\n try {\n track = await module.createLocalVideoTrack(deviceId === null ? {} : { deviceId });\n } catch (error) {\n throw normalizeDeviceError(error, \"meet.cameraPreview\");\n }\n const target = track as unknown as {\n setProcessor(processor: unknown): Promise<void>;\n stopProcessor(): Promise<void>;\n };\n async function apply(next: VideoEffect): Promise<void> {\n if (next.kind === \"none\") {\n await target.stopProcessor();\n return;\n }\n const processors = await import(\"@livekit/track-processors\");\n await target.setProcessor(\n next.kind === \"blur\"\n ? processors.BackgroundBlur(next.radius ?? 12)\n : processors.VirtualBackground(next.imageUrl),\n );\n }\n if (effect.kind !== \"none\" && videoEffectsSupported()) {\n try {\n await apply(effect);\n } catch {\n // The preview still shows the camera; the settings say the effect failed.\n }\n }\n return {\n attach(element) {\n track.attach(element);\n },\n setEffect: apply,\n stop() {\n track.stop();\n track.detach();\n },\n };\n}\n","\"use client\";\n\n/**\n * THE HOOKS. Thin shells over the framework-free core — every one of them\n * exists so a consumer never writes the sequence itself.\n *\n * The rule that shapes this file: a hook returns DATA and ACTIONS, never a\n * \"you must also call this on unmount\" instruction. `useTrack` hands back a ref\n * callback whose cleanup is the detach; `useRoom` disposes with the component.\n * A correct-usage checklist in a README is a bug waiting for a deadline.\n *\n * 🚨 **NO HOOK IN THIS FILE THROWS WHEN THE PROVIDER IS INERT** (0.2.1).\n * `<MeetProvider>` is deliberately inert until a client, an organization and an\n * identity are all real — which is EVERY server render, every signed-out\n * visitor, and every moment before the active organization hydrates. Through\n * 0.2.0 these hooks called `useRequiredMeetHost()`, so the exact three-line\n * integration the README prescribes returned a 500 on every route for every\n * such visitor, and the first real consumer had to wrap our own components in\n * a host-side guard (register MRI-D1). A hook now reports an inert runtime as\n * DATA — empty lists, `canCall: false`, `available: false` — so the components\n * above render nothing or an honest sentence on their own. Only an ACTION\n * invoked with no runtime fails, and it fails loudly with a remedy; it can not\n * be reached from a surface that renders correctly.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { MeetAnswerCoverage } from \"../core/ai\";\nimport { IDLE_MEDIA, listenOnlyNotice, type LocalMediaState } from \"../core/attendance\";\nimport { MeetError } from \"../core/errors\";\nimport {\n noteTakerLabel,\n noteTakerParticipant,\n noteTakerStatus,\n type NoteTakerStatus,\n} from \"../core/note-taker\";\nimport { displayNameFor, type NameBook } from \"../core/names\";\nimport { readableTranscript } from \"../core/transcript\";\n\n/** A stable empty book, so `useMemo` does not re-run on every render. */\nconst EMPTY_NAMES: NameBook = {};\nimport { END_MEETING_NOT_SERVED } from \"../core/meetings\";\nimport { computeStage, DEFAULT_PAGE_SIZE, type Stage } from \"../core/layout\";\nimport { canModerateParticipant } from \"../core/meetings\";\nimport { isRecordingInFlight, recordingLabel } from \"../core/recording\";\nimport type { MeetingSession } from \"../core/meetings\";\nimport type { JoinRequest, RoomEngine } from \"../core/room\";\nimport type { ModerationRequest, ModerationResult } from \"../core/in-room\";\nimport {\n DEFAULT_EFFECTS,\n REACTION_TTL_MS,\n type MediaEffects,\n type ModerationNotice,\n} from \"../core/store\";\nimport { isHostRole } from \"../core/types\";\nimport {\n guestRecordAccessSetting,\n activeWrapUpSummary,\n loadGuestMeetingRecord,\n loadMeetingRecord,\n setGuestRecordAccess,\n type GuestRecordAccessResolution,\n type GuestRecordAccessSetting,\n type MeetingRecordBundle,\n} from \"../core/record\";\nimport type {\n CallInvite,\n CallMode,\n LobbyEntry,\n MeetParticipant,\n MeetingId,\n MeetingNote,\n MeetingRecord,\n ParticipantIdentity,\n RoomName,\n StageLayout,\n TranscriptSource,\n UserId,\n WrapUpAnnouncement,\n} from \"../core/types\";\nimport {\n useCanRecord,\n useIsHost,\n useRole,\n useMeetHost,\n useMeetSnapshot,\n type MeetHost,\n} from \"./provider\";\n\n/**\n * The ONE sentence every hook says when an action is invoked with no runtime.\n * It names the state and the fix; it never returns a silent no-op, because a\n * button that quietly does nothing is the failure this package exists to avoid.\n */\nconst NO_RUNTIME_REMEDY =\n \"Render this inside a <MeetProvider> that has a Supabase client, an organization id and \" +\n \"an identity (userId or guestName). The provider stays inert until all three are real, \" +\n \"and while it is inert this package's components render nothing rather than a dead control.\";\n\nfunction noRuntime(action: string): MeetError {\n return new MeetError(\n \"misconfigured\",\n `[@ai-matrx/meet] ${action}: there is no meet runtime on this tree.`,\n NO_RUNTIME_REMEDY,\n );\n}\n\nfunction requireHost(host: MeetHost | null, action: string): MeetHost {\n if (host === null) throw noRuntime(action);\n return host;\n}\n\nfunction requireEngine(engine: RoomEngine | null, action: string): RoomEngine {\n if (engine === null) throw noRuntime(action);\n return engine;\n}\n\nfunction requireSession(session: MeetingSession | null, action: string): MeetingSession {\n if (session === null) throw noRuntime(action);\n return session;\n}\n\nexport interface UseRoomResult {\n readonly phase: string;\n readonly participants: readonly MeetParticipant[];\n readonly failure: { readonly message: string; readonly remedy: string } | null;\n join: (request: JoinRequest) => Promise<void>;\n leave: () => Promise<void>;\n toggleMicrophone: () => Promise<void>;\n toggleCamera: () => Promise<void>;\n toggleScreenShare: () => Promise<void>;\n toggleHand: () => Promise<void>;\n react: (emoji: string) => Promise<void>;\n /** To EVERYONE — saved through the server (Meet wave 2). */\n sendChat: (text: string) => Promise<void>;\n /** To ONE person — data plane only, never saved. */\n sendPrivateChat: (to: ParticipantIdentity, text: string) => Promise<void>;\n pin: (identity: ParticipantIdentity | null) => void;\n setLayout: (layout: StageLayout) => void;\n readonly local: MeetParticipant | null;\n}\n\nexport function useRoom(): UseRoomResult {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const engine = host?.engine ?? null;\n\n const local =\n snapshot?.participants.find(\n (participant) => participant.identity === snapshot.localIdentity,\n ) ?? null;\n\n return {\n phase: snapshot?.phase ?? \"idle\",\n participants: snapshot?.participants ?? [],\n failure: snapshot?.failure ?? null,\n local,\n join: useCallback(\n async (request: JoinRequest) => requireEngine(engine, \"join\").join(request),\n [engine],\n ),\n leave: useCallback(async () => requireEngine(engine, \"leave\").leave(), [engine]),\n toggleMicrophone: useCallback(\n async () =>\n requireEngine(engine, \"toggleMicrophone\").setMicrophoneEnabled(\n !(local?.micEnabled ?? false),\n ),\n [engine, local],\n ),\n toggleCamera: useCallback(\n async () =>\n requireEngine(engine, \"toggleCamera\").setCameraEnabled(!(local?.cameraEnabled ?? false)),\n [engine, local],\n ),\n toggleScreenShare: useCallback(\n async () =>\n requireEngine(engine, \"toggleScreenShare\").setScreenShareEnabled(\n !(local?.screenSharing ?? false),\n ),\n [engine, local],\n ),\n toggleHand: useCallback(\n async () => requireEngine(engine, \"toggleHand\").raiseHand(!(local?.handRaised ?? false)),\n [engine, local],\n ),\n react: useCallback(\n async (emoji: string) => requireEngine(engine, \"react\").react(emoji),\n [engine],\n ),\n sendChat: useCallback(\n async (text: string) => {\n if (host === null) throw noRuntime(\"sendChat\");\n await host.inRoom.sendChat(text);\n },\n [host],\n ),\n sendPrivateChat: useCallback(\n async (to: ParticipantIdentity, text: string) =>\n requireEngine(engine, \"sendPrivateChat\").sendPrivateChat(to, text),\n [engine],\n ),\n pin: useCallback(\n (identity: ParticipantIdentity | null) => requireEngine(engine, \"pin\").pin(identity),\n [engine],\n ),\n setLayout: useCallback(\n (layout: StageLayout) => requireEngine(engine, \"setLayout\").setLayout(layout),\n [engine],\n ),\n };\n}\n\n/** The stage, recomputed only when the roster or the layout actually changes. */\nexport function useStage(pageSize = DEFAULT_PAGE_SIZE): Stage {\n const snapshot = useMeetSnapshot();\n const [page, setPage] = useState(0);\n const stage = useMemo(\n () =>\n computeStage({\n participants: snapshot?.participants ?? [],\n layout: snapshot?.layout ?? \"grid\",\n pinned: snapshot?.pinned ?? null,\n spotlight: snapshot?.spotlight ?? null,\n activeSpeakers: snapshot?.activeSpeakers ?? [],\n pageSize,\n page,\n }),\n [snapshot, pageSize, page],\n );\n // Clamp back into range when people leave — a page that scrolled past the\n // end must not render an empty stage.\n useEffect(() => {\n if (page > stage.pageCount - 1) setPage(Math.max(0, stage.pageCount - 1));\n }, [page, stage.pageCount]);\n return stage;\n}\n\n/**\n * Attach a participant's media to an element. The returned ref callback's\n * CLEANUP is the detach — there is nothing a consumer can forget to call.\n */\nexport function useTrack(\n identity: ParticipantIdentity | null,\n kind: \"camera\" | \"microphone\" | \"screen\",\n): (element: HTMLMediaElement | null) => void {\n const host = useMeetHost();\n const detachRef = useRef<(() => void) | null>(null);\n return useCallback(\n (element: HTMLMediaElement | null) => {\n detachRef.current?.();\n detachRef.current = null;\n if (element === null || identity === null || host === null) return;\n detachRef.current = host.engine.attach(identity, kind, element);\n },\n [host, identity, kind],\n );\n}\n\nexport interface UseCallsResult {\n readonly incoming: readonly CallInvite[];\n readonly outgoing: CallInvite | null;\n /** `null` for a guest identity — the UI renders nothing rather than a dead button. */\n readonly canCall: boolean;\n call: (people: readonly UserId[], mode: CallMode) => Promise<CallInvite>;\n accept: (invite: CallInvite) => Promise<void>;\n decline: (invite: CallInvite, message?: string) => Promise<void>;\n cancel: (invite: CallInvite) => Promise<void>;\n}\n\nexport function useCalls(): UseCallsResult {\n // NOT `useRequiredMeetHost`. `<IncomingCallHost/>` is mounted app-wide by\n // contract, so it renders on every server render and for every signed-out\n // visitor — states in which this provider is correctly inert.\n const host = useMeetHost();\n const center = host?.calls ?? null;\n const [, force] = useState(0);\n\n // The call center is not a store (it is a lifecycle object), so a ring must\n // re-render this hook. A 500ms poll would be a lie about liveness; the\n // provider's onIncoming already fires, so we re-render on the same tick.\n useEffect(() => {\n if (center === null) return undefined;\n const timer = setInterval(() => force((value) => value + 1), 1_000);\n return () => clearInterval(timer);\n }, [center]);\n\n return {\n incoming: center?.incoming() ?? [],\n outgoing: center?.outgoing() ?? null,\n canCall: center !== null,\n call: useCallback(\n async (people: readonly UserId[], mode: CallMode) => {\n if (center === null) {\n throw noRuntime(\n host === null ? \"call\" : \"call (a guest identity has no calling surface, D6)\",\n );\n }\n const invite = await center.call({ people, mode });\n force((value) => value + 1);\n return invite;\n },\n [center, host],\n ),\n accept: useCallback(\n async (invite: CallInvite) => {\n if (center === null || host === null) return;\n await center.accept(invite.id, invite.mode);\n await host.engine.join({ roomName: invite.roomName, mode: invite.mode });\n force((value) => value + 1);\n },\n [center, host],\n ),\n decline: useCallback(\n async (invite: CallInvite, message?: string) => {\n if (center === null) return;\n await center.decline(invite.id, message);\n force((value) => value + 1);\n },\n [center],\n ),\n cancel: useCallback(\n async (invite: CallInvite) => {\n if (center === null) return;\n await center.cancel(invite.id);\n force((value) => value + 1);\n },\n [center],\n ),\n };\n}\n\nexport interface UseLobbyResult {\n readonly waiting: readonly LobbyEntry[];\n readonly canAdmit: boolean;\n admit: (entry: LobbyEntry) => Promise<void>;\n deny: (entry: LobbyEntry) => Promise<void>;\n admitAll: () => Promise<void>;\n knock: (roomName: RoomName) => void;\n}\n\nexport function useLobby(): UseLobbyResult {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const isHost = useIsHost();\n const session = host?.meetings ?? null;\n return {\n waiting: (snapshot?.lobby ?? []).filter((entry) => entry.state === \"knocking\"),\n // No runtime means no host powers — `<LobbyPanel>` renders nothing rather\n // than an admit button that would throw.\n canAdmit: session !== null && isHost,\n admit: useCallback(\n async (entry: LobbyEntry) => requireSession(session, \"admit\").admit(entry, true),\n [session],\n ),\n deny: useCallback(\n async (entry: LobbyEntry) => requireSession(session, \"deny\").admit(entry, false),\n [session],\n ),\n admitAll: useCallback(\n async () => requireSession(session, \"admitAll\").admitAll(),\n [session],\n ),\n knock: useCallback(\n (roomName: RoomName) => requireSession(session, \"knock\").knock(roomName),\n [session],\n ),\n };\n}\n\nexport interface UseRecordingResult {\n readonly state: string;\n readonly label: string | null;\n readonly canStart: boolean;\n readonly canStop: boolean;\n readonly consentNotice: string | null;\n start: () => Promise<void>;\n stop: () => Promise<void>;\n}\n\nexport function useRecording(): UseRecordingResult {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n // 🚨 THE SERVER'S GRANT, not `isHost` (MRI-A11). aidream computes\n // `can_record = is_host AND policy == host-controlled` and puts it on the\n // token and the roster attribute; the policy half is why a host of an\n // `always-on` meeting correctly gets NO control. The policy check below is\n // kept as the package's own agreement with that rule, never as a substitute.\n const canRecord = useCanRecord();\n const meeting = snapshot?.meeting ?? null;\n const state = snapshot?.recording ?? \"idle\";\n // 🚨 NOT `state === \"idle\"` (MRI-A16). Once the durable states actually\n // arrive, a meeting whose recording finished sits on `available`, and asking\n // for `idle` made the Start control vanish for the rest of the session.\n const canStart =\n host !== null && canRecord && host.recording.canStart(meeting, true) && !isRecordingInFlight(state);\n\n return {\n state,\n label: recordingLabel(state),\n canStart,\n // `stopping` is already stopping; the other in-flight states can be.\n canStop: host !== null && canRecord && (state === \"recording\" || state === \"starting\"),\n consentNotice: host?.recording.consentNotice(meeting) ?? null,\n start: useCallback(async () => {\n const live = requireHost(host, \"startRecording\");\n if (meeting === null || live.identity.userId === null) return;\n await live.recording.start({\n meetingId: meeting.id,\n roomName: meeting.roomName,\n by: live.identity.userId,\n });\n }, [host, meeting]),\n stop: useCallback(async () => {\n const live = requireHost(host, \"stopRecording\");\n if (meeting === null || live.identity.userId === null) return;\n await live.recording.stop({ meetingId: meeting.id, by: live.identity.userId });\n }, [host, meeting]),\n };\n}\n\n/** One line of the transcript, as a panel renders it. */\nexport interface TranscriptLine {\n readonly id: string;\n /** Who said it, as the room knows them. Surfaces group by THIS, not by name. */\n readonly identity: ParticipantIdentity;\n readonly speaker: string;\n readonly text: string;\n readonly final: boolean;\n /** `caption` is a live hint; `record` is the durable transcript (D16). */\n readonly source: TranscriptSource;\n}\n\nexport interface UseMeetAiResult {\n /** The note-taker's honest state, and the server's refusal if there was one. */\n readonly noteTaker: NoteTakerStatus;\n /** The sentence for that state. Never a bare enum, never a spinner. */\n readonly noteTakerLabel: string;\n /** True only for a host of a meeting whose AI is on. Guests get no control. */\n readonly canControlNoteTaker: boolean;\n /** Live-window notes, oldest first. */\n readonly notes: readonly MeetingNote[];\n readonly decisions: readonly MeetingNote[];\n readonly actionItems: readonly MeetingNote[];\n /** The wrap-up summary, once the meeting has produced one. */\n readonly summary: MeetingNote | null;\n /**\n * The wrap-up pass ANNOUNCED itself into this room (MRI-A12). `null` means it\n * has not been announced HERE — never that no summary exists. The ordinary\n * ending path deletes the LiveKit room before the pass runs, so this is\n * normally null and the summary is read on the post-meeting record.\n */\n readonly wrapUp: WrapUpAnnouncement | null;\n readonly transcript: readonly TranscriptLine[];\n readonly asking: boolean;\n /** The answer SO FAR. It grows while the answer streams. */\n readonly answer: string | null;\n readonly coverage: MeetAnswerCoverage | null;\n /** The server's phase while an answer is being built. */\n readonly phase: string | null;\n readonly error: { readonly message: string; readonly remedy: string } | null;\n ask: (question: string) => Promise<void>;\n startNoteTaker: () => Promise<void>;\n stopNoteTaker: () => Promise<void>;\n}\n\n/**\n * THE MEETING ASSISTANT, as a surface needs it.\n *\n * Everything below is DATA, including every failure. There is no state in which\n * this hook returns a spinner with nothing behind it: the note-taker is in one\n * of five named states or the server refused with a sentence, and an answer is\n * either arriving (visibly, token by token) or has failed with a remedy.\n */\nexport function useMeetAi(): UseMeetAiResult {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const isHost = useIsHost();\n const [asking, setAsking] = useState(false);\n const [answer, setAnswer] = useState<string | null>(null);\n const [coverage, setCoverage] = useState<MeetAnswerCoverage | null>(null);\n const [phase, setPhase] = useState<string | null>(null);\n const [error, setError] = useState<{ message: string; remedy: string } | null>(null);\n const ai = host?.ai ?? null;\n const meeting = snapshot?.meeting ?? null;\n const participants = snapshot?.participants ?? [];\n const notes = snapshot?.notes ?? [];\n const wrapUp = snapshot?.wrapUp ?? null;\n\n const status = useMemo(\n () =>\n noteTakerStatus({\n meeting,\n participants,\n refusal: snapshot?.noteTakerRefusal ?? null,\n }),\n [meeting, participants, snapshot?.noteTakerRefusal],\n );\n\n const names = snapshot?.names ?? EMPTY_NAMES;\n const transcript = useMemo(\n () =>\n readableTranscript(snapshot?.transcript ?? []).map((line) => ({\n id: line.id,\n identity: line.identity,\n // 🚨 RESOLVED, not rendered raw (MRI-A16). A line stamped before its\n // speaker's name was known — a durable row that beat the roster, a\n // caption from someone who has since left — is re-attributed the moment\n // anything learns the name, in BOTH lanes, so the host and the guest\n // never read two different names for one speaker again (MRI-C8).\n speaker: displayNameFor(names, line.identity, line.speaker),\n text: line.text,\n final: line.final,\n source: line.source,\n })),\n [snapshot?.transcript, names],\n );\n\n const dispatchNoteTaker = useCallback(\n async (run: () => Promise<unknown>) => {\n setError(null);\n try {\n await run();\n } catch (thrown) {\n // THE SERVER'S SENTENCE REACHES THE SCREEN. A dispatch that failed and\n // said nothing is a meeting everyone believes is being minuted.\n setError({\n message: (thrown as Error).message,\n remedy:\n (thrown as { remedy?: string }).remedy ??\n \"The note-taker action could not be confirmed. Check its current state and try again.\",\n });\n }\n },\n [],\n );\n\n return {\n noteTaker: status,\n noteTakerLabel: noteTakerLabel(status),\n // A guest cannot dispatch an agent, and neither can anyone in a meeting\n // whose AI is off. The control is ABSENT for them, never disabled-looking.\n canControlNoteTaker:\n ai !== null && meeting !== null && meeting.aiEnabled && isHost && host?.identity.userId !== null,\n notes: notes.filter((note) => note.kind === \"note\" && note.role === null),\n // D20: the wrap-up is the authoritative post-meeting set. A window-written\n // decision the wrap-up superseded stays in `notes` — the timeline — and is\n // not listed a second time as a decision that was made.\n decisions: notes.filter((note) => note.kind === \"decision\" && note.supersededBy === null),\n actionItems: notes.filter(\n (note) => note.kind === \"action-item\" && note.supersededBy === null,\n ),\n summary: activeWrapUpSummary(notes),\n wrapUp,\n transcript,\n asking,\n answer,\n coverage,\n phase,\n error,\n ask: useCallback(\n async (question: string) => {\n if (ai === null || meeting === null) return;\n setAsking(true);\n setError(null);\n setAnswer(null);\n setCoverage(null);\n setPhase(null);\n try {\n const result = await ai.ask({\n meetingId: meeting.id,\n question,\n // THE ANSWER RENDERS AS IT ARRIVES. Waiting for the last token to\n // show the first is a spinner wearing an answer's clothes.\n onText: (text) => setAnswer(text),\n onPhase: (value) => setPhase(value),\n });\n setAnswer(result.text);\n setCoverage(result.coverage);\n } catch (thrown) {\n setError({\n message: (thrown as Error).message,\n remedy:\n (thrown as { remedy?: string }).remedy ??\n \"The assistant could not answer. Nothing was changed by the attempt.\",\n });\n } finally {\n setAsking(false);\n setPhase(null);\n }\n },\n [ai, meeting],\n ),\n startNoteTaker: useCallback(async () => {\n if (ai === null || meeting === null) return;\n await dispatchNoteTaker(() =>\n ai.startNoteTaker({ meetingId: meeting.id, roomName: meeting.roomName }),\n );\n }, [ai, meeting, dispatchNoteTaker]),\n stopNoteTaker: useCallback(async () => {\n if (ai === null || meeting === null) return;\n await dispatchNoteTaker(() => ai.stopNoteTaker({ meetingId: meeting.id }));\n }, [ai, meeting, dispatchNoteTaker]),\n };\n}\n\n/**\n * ENDING THE MEETING FOR EVERYONE — a host control with an honest failure.\n *\n * `POST /v1/meet/end` is served by MRI-A6. A server that has not landed it\n * answers 404, and this hook reports that as the sentence\n * `END_MEETING_NOT_SERVED` rather than pretending the meeting ended or leaving\n * a button that appears to do nothing.\n */\nexport interface UseEndMeetingResult {\n readonly canEnd: boolean;\n readonly ending: boolean;\n readonly ended: boolean;\n /** The honest sentence when the attempt did not end the meeting. */\n readonly notice: string | null;\n end: () => Promise<void>;\n}\n\nexport function useEndMeeting(): UseEndMeetingResult {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const isHost = useIsHost();\n const [ending, setEnding] = useState(false);\n const [notice, setNotice] = useState<string | null>(null);\n const meeting = snapshot?.meeting ?? null;\n const session = host?.meetings ?? null;\n\n return {\n canEnd: session !== null && isHost && meeting !== null && meeting.endedAt === null,\n ending,\n ended: meeting?.endedAt !== null && meeting?.endedAt !== undefined,\n notice,\n end: useCallback(async () => {\n const live = requireSession(session, \"endForEveryone\");\n setEnding(true);\n setNotice(null);\n try {\n const result = await live.endForEveryone();\n if (!result.served) {\n // NOT A DEAD BUTTON AND NOT A LIE: the route is pinned in the\n // package's contract and this server has not landed it yet (MRI-A6).\n setNotice(END_MEETING_NOT_SERVED);\n }\n } catch (thrown) {\n const remedy = (thrown as { remedy?: string }).remedy;\n setNotice(\n remedy !== undefined\n ? `${(thrown as Error).message} ${remedy}`\n : (thrown as Error).message,\n );\n } finally {\n setEnding(false);\n }\n }, [session]),\n };\n}\n\n/**\n * THE CONSENT NOTICE (D10) — a property of this package, never a prop.\n *\n * Returns the sentence every participant must see while an agent is in the\n * room, or `null` when none is. There is deliberately no way to turn it off:\n * the org's policy decides whether a note-taker may run, and it never decides\n * whether the people in the room are told about it.\n */\nexport function useConsentNotice(): string | null {\n const snapshot = useMeetSnapshot();\n const agent = noteTakerParticipant(snapshot?.participants ?? []);\n if (agent === null) return null;\n return (\n `${agent.displayName} is in this meeting: it is transcribing what is said and ` +\n \"writing notes everyone here can read.\"\n );\n}\n\n/**\n * What the LOCAL participant is actually publishing, and why not when it is not.\n * Read this — never the roster's `micEnabled` — to decide whether to tell\n * someone they cannot be heard: the roster reflects the media plane, this\n * reflects the ATTEMPT, including one the browser refused outright (there is no\n * track to be un-muted in that case, so the roster would simply say `false`\n * with no reason attached).\n */\nexport function useLocalMedia(): LocalMediaState {\n const snapshot = useMeetSnapshot();\n return snapshot?.media ?? IDLE_MEDIA;\n}\n\n/**\n * The listen-only sentence, or `null` while the microphone is live. The remedy,\n * when the device was refused rather than declined, is on\n * `useLocalMedia().microphone.unavailable`.\n */\nexport function useListenOnlyNotice(): string | null {\n return listenOnlyNotice(useLocalMedia());\n}\n\n/** Live reactions, already expired. Rendering stale confetti is the alternative. */\nexport function useReactions(): readonly { id: string; emoji: string }[] {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const store = host?.store ?? null;\n useEffect(() => {\n if (store === null) return undefined;\n const timer = setInterval(() => store.expireReactions(Date.now()), REACTION_TTL_MS / 2);\n return () => clearInterval(timer);\n }, [store]);\n return snapshot?.reactions ?? [];\n}\n\n/** A ticking duration for the call header. One timer, not one per component. */\nexport function useElapsed(startedAt: string | null): number {\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n if (startedAt === null) return undefined;\n const timer = setInterval(() => setNow(Date.now()), 1_000);\n return () => clearInterval(timer);\n }, [startedAt]);\n if (startedAt === null) return 0;\n return Math.max(0, now - Date.parse(startedAt));\n}\n\n/** Whether the local actor may moderate a given participant. One rank check. */\nexport function useCanModerate(target: MeetParticipant | undefined): boolean {\n const snapshot = useMeetSnapshot();\n const role = useRole();\n const me = snapshot?.participants.find(\n (participant) => participant.identity === snapshot.localIdentity,\n );\n // The EFFECTIVE role (token ∪ roster attribute — MRI-A11), not whichever of\n // the two the roster happened to carry this tick.\n return canModerateParticipant(me === undefined ? undefined : { ...me, role }, target);\n}\n\n/**\n * 🚨 EVERY HOST POWER, THROUGH THE SERVER (MRI-A11 → Meet wave 2).\n *\n * `canModerate` is the rank check — a host outranks a co-host outranks\n * everyone, and NOBODY may moderate themselves — so a surface renders a control\n * only where it would actually be honoured. The act itself is a server call\n * (`core/in-room.ts`): through 0.7.x mute and remove were data packets nothing\n * listened to, which made them buttons that did nothing.\n *\n * `notice` is the server's last sentence (or refusal) for the actor — a control\n * that acted and said nothing is indistinguishable from one that did nothing.\n */\nexport interface UseHostControlsResult {\n readonly isHost: boolean;\n /** The host itself (not a co-host) — only the host hands the meeting over. */\n readonly isOwner: boolean;\n readonly notice: { readonly text: string; readonly failed: boolean } | null;\n readonly busy: boolean;\n clearNotice: () => void;\n canModerate: (target: MeetParticipant) => boolean;\n run: (request: ModerationRequest) => Promise<ModerationResult | null>;\n mute: (target: MeetParticipant) => Promise<void>;\n remove: (target: MeetParticipant) => Promise<void>;\n}\n\nexport function useHostControls(): UseHostControlsResult {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const role = useRole();\n const me = snapshot?.participants.find(\n (participant) => participant.identity === snapshot.localIdentity,\n );\n const actor = me === undefined ? undefined : { ...me, role };\n const [busy, setBusy] = useState(false);\n const inRoom = host?.inRoom ?? null;\n const store = host?.store ?? null;\n const notice = snapshot?.actionNotice ?? null;\n const setNotice = useCallback(\n (next: { text: string; failed: boolean } | null) =>\n store?.patch({ actionNotice: next === null ? null : { ...next, at: Date.now() } }),\n [store],\n );\n\n const run = useCallback(\n async (request: ModerationRequest): Promise<ModerationResult | null> => {\n if (inRoom === null) throw noRuntime(`moderate(${request.action})`);\n setBusy(true);\n try {\n const result = await inRoom.moderate(request);\n setNotice({ text: result.message, failed: false });\n return result;\n } catch (thrown) {\n const error = thrown as { message?: string; remedy?: string };\n setNotice({\n text: [error.message, error.remedy].filter(Boolean).join(\" \"),\n failed: true,\n });\n return null;\n } finally {\n setBusy(false);\n }\n },\n [inRoom, setNotice],\n );\n\n return {\n isHost: isHostRole(role),\n isOwner: role === \"host\",\n notice,\n busy,\n clearNotice: useCallback(() => setNotice(null), [setNotice]),\n canModerate: useCallback(\n (target: MeetParticipant) => canModerateParticipant(actor, target),\n [actor],\n ),\n run,\n mute: useCallback(\n async (target: MeetParticipant) => {\n await run({ action: \"mute\", identity: target.identity });\n },\n [run],\n ),\n remove: useCallback(\n async (target: MeetParticipant) => {\n await run({ action: \"remove\", identity: target.identity });\n },\n [run],\n ),\n };\n}\n\n/**\n * THE HAND QUEUE — raised hands in the order they went up (Meet wave 2).\n * First raised, first called on; a late joiner learns the order from each\n * client's re-announcement (`room.ts`).\n */\nexport function useHandQueue(): readonly MeetParticipant[] {\n const snapshot = useMeetSnapshot();\n return useMemo(\n () =>\n (snapshot?.participants ?? [])\n .filter((participant) => participant.handRaised)\n .sort((a, b) => (a.handRaisedAt ?? 0) - (b.handRaisedAt ?? 0)),\n [snapshot?.participants],\n );\n}\n\n/** This participant's noise suppression and background, and the setter. */\nexport interface UseMediaEffectsResult {\n readonly effects: MediaEffects;\n /** False = this browser cannot run a background effect; the control is absent. */\n readonly backgroundsSupported: boolean;\n set: (next: Partial<MediaEffects>) => Promise<void>;\n}\n\nexport function useMediaEffects(): UseMediaEffectsResult {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const engine = host?.engine ?? null;\n return {\n effects: snapshot?.effects ?? DEFAULT_EFFECTS,\n backgroundsSupported: engine?.supportsVideoEffects() ?? false,\n set: useCallback(\n async (next: Partial<MediaEffects>) => requireEngine(engine, \"setEffects\").setEffects(next),\n [engine],\n ),\n };\n}\n\n/** What a host last did to THIS participant, and a way to dismiss it. */\nexport function useModerationNotice(): { notice: ModerationNotice | null; dismiss: () => void } {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n return {\n notice: snapshot?.moderationNotice ?? null,\n dismiss: useCallback(() => host?.store.patch({ moderationNotice: null }), [host]),\n };\n}\n\n/**\n * A live microphone level, 0..1, for a meter. Reads the given stream through an\n * `AnalyserNode`; returns 0 while there is none. One animation frame loop,\n * closed with the stream.\n */\nexport function useAudioLevel(stream: MediaStream | null): number {\n const [level, setLevel] = useState(0);\n useEffect(() => {\n if (stream === null || stream.getAudioTracks().length === 0) {\n setLevel(0);\n return undefined;\n }\n const Context =\n (globalThis as { AudioContext?: typeof AudioContext }).AudioContext ??\n (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (Context === undefined) return undefined;\n const context = new Context();\n const source = context.createMediaStreamSource(stream);\n const analyser = context.createAnalyser();\n analyser.fftSize = 512;\n source.connect(analyser);\n const samples = new Uint8Array(analyser.fftSize);\n let frame = 0;\n const tick = () => {\n analyser.getByteTimeDomainData(samples);\n let peak = 0;\n for (const sample of samples) peak = Math.max(peak, Math.abs(sample - 128) / 128);\n setLevel((previous) => (Math.abs(previous - peak) > 0.02 ? peak : previous));\n frame = requestAnimationFrame(tick);\n };\n frame = requestAnimationFrame(tick);\n return () => {\n cancelAnimationFrame(frame);\n source.disconnect();\n void context.close();\n };\n }, [stream]);\n return level;\n}\n\n/**\n * THE KEYBOARD SHORTCUTS (Meet wave 2) — Google Meet's own chords, so nobody\n * relearns anything: ⌘/Ctrl+D mute, ⌘/Ctrl+E camera, ⌘/Ctrl+Alt+H hand,\n * ⌘/Ctrl+Alt+C chat, ⌘/Ctrl+Alt+P people, Shift+? the shortcuts sheet. Never\n * fires while the person is typing in a field.\n */\nexport const MEET_SHORTCUTS: readonly {\n readonly id: \"mic\" | \"camera\" | \"hand\" | \"chat\" | \"people\" | \"help\";\n readonly keys: string;\n readonly label: string;\n}[] = [\n { id: \"mic\", keys: \"⌘/Ctrl + D\", label: \"Mute or unmute your microphone\" },\n { id: \"camera\", keys: \"⌘/Ctrl + E\", label: \"Turn your camera on or off\" },\n { id: \"hand\", keys: \"⌘/Ctrl + Alt + H\", label: \"Raise or lower your hand\" },\n { id: \"chat\", keys: \"⌘/Ctrl + Alt + C\", label: \"Open or close chat\" },\n { id: \"people\", keys: \"⌘/Ctrl + Alt + P\", label: \"Open or close people\" },\n { id: \"help\", keys: \"Shift + ?\", label: \"Show keyboard shortcuts\" },\n];\n\nexport function useMeetShortcuts(\n handlers: Partial<Record<(typeof MEET_SHORTCUTS)[number][\"id\"], () => void>>,\n): void {\n const ref = useRef(handlers);\n ref.current = handlers;\n useEffect(() => {\n const target = (globalThis as { window?: Window }).window;\n if (target === undefined) return undefined;\n const onKey = (event: KeyboardEvent) => {\n const element = event.target as HTMLElement | null;\n const typing =\n element !== null &&\n (element.isContentEditable ||\n element.tagName === \"INPUT\" ||\n element.tagName === \"TEXTAREA\" ||\n element.tagName === \"SELECT\");\n const mod = event.metaKey || event.ctrlKey;\n const key = event.key.toLowerCase();\n let id: (typeof MEET_SHORTCUTS)[number][\"id\"] | null = null;\n if (mod && !event.altKey && !event.shiftKey && key === \"d\") id = \"mic\";\n else if (mod && !event.altKey && !event.shiftKey && key === \"e\") id = \"camera\";\n else if (mod && event.altKey && (event.code === \"KeyH\" || key === \"h\")) id = \"hand\";\n else if (mod && event.altKey && (event.code === \"KeyC\" || key === \"c\")) id = \"chat\";\n else if (mod && event.altKey && (event.code === \"KeyP\" || key === \"p\")) id = \"people\";\n else if (!mod && !typing && event.key === \"?\") id = \"help\";\n if (id === null) return;\n const handler = ref.current[id];\n if (handler === undefined) return;\n // ⌘D is \"bookmark\" and ⌘E is \"search\" in browsers: the meeting wins while\n // it is on screen, exactly as it does in Meet.\n event.preventDefault();\n handler();\n };\n target.addEventListener(\"keydown\", onKey);\n return () => target.removeEventListener(\"keydown\", onKey);\n }, []);\n}\n\nexport function useMeeting(): MeetingRecord | null {\n return useMeetSnapshot()?.meeting ?? null;\n}\n\nexport function useMeetingId(): MeetingId | null {\n return useMeetSnapshot()?.meeting?.id ?? null;\n}\n\n/* ------------------------------------------------------ the meeting record */\n\n/**\n * THE MEETING AFTER THE MEETING (MRI-D2).\n *\n * A durable link outlives the room (R3), and until this hook existed it\n * resolved to a pre-join screen for a room nobody could enter — the summary,\n * decisions, action items, live notes, transcript and recording were reachable\n * only from SQL. This loads all of it from durable rows, states what the reader\n * is not allowed to see instead of rendering emptiness, and keeps the Q&A box\n * working against the record: `/intelligence/ask` reads the same durable rows\n * and answers a signed-in member long after the room closed.\n *\n * It is deliberately independent of the room store: nothing here needs a\n * LiveKit connection, a token, or a joined participant.\n */\nexport interface UseMeetingRecordResult {\n readonly loading: boolean;\n readonly record: MeetingRecordBundle | null;\n /** A failure that stopped the WHOLE record loading. Partial refusals are in\n * `record.restrictions` — this is null whenever a record exists. */\n readonly failure: { readonly message: string; readonly remedy: string } | null;\n /** Q&A against the durable record. Streams, exactly as it does in-room. */\n readonly asking: boolean;\n readonly answer: string | null;\n readonly coverage: MeetAnswerCoverage | null;\n readonly askError: { readonly message: string; readonly remedy: string } | null;\n ask: (question: string) => Promise<void>;\n reload: () => void;\n}\n\nexport function useMeetingRecord(meeting: MeetingRecord | null): UseMeetingRecordResult {\n const host = useMeetHost();\n const repository = host?.repository ?? null;\n const ai = host?.ai ?? null;\n const readerId = host?.identity.userId ?? null;\n const [recordReaderId, setRecordReaderId] = useState<typeof readerId>(readerId);\n const [record, setRecord] = useState<MeetingRecordBundle | null>(null);\n const [loading, setLoading] = useState(true);\n const [failure, setFailure] = useState<{ message: string; remedy: string } | null>(null);\n const [nonce, setNonce] = useState(0);\n const [asking, setAsking] = useState(false);\n const [answer, setAnswer] = useState<string | null>(null);\n const [coverage, setCoverage] = useState<MeetAnswerCoverage | null>(null);\n const [askError, setAskError] = useState<{ message: string; remedy: string } | null>(null);\n\n const meetingId = meeting?.id ?? null;\n\n const api = host?.api ?? null;\n const tokens = host?.tokens ?? null;\n const roomName = meeting?.roomName ?? null;\n\n useEffect(() => {\n if (repository === null || meeting === null || meetingId === null) return undefined;\n let live = true;\n setLoading(true);\n setFailure(null);\n setRecord(null);\n // 🚨 TWO READERS, TWO DOORS, ONE BUNDLE (MRF-1).\n //\n // A signed-in member reads the record DIRECT from Supabase under RLS, as\n // they always have. A guest has no database at all — `anon` holds no grant\n // on the four org-scoped tables and widening it is forbidden (MRI-A10) — so\n // they read what the organization shares through `GET /v1/meet/record`,\n // authorized by the pass this device kept from the meeting. Both produce\n // the same `MeetingRecordBundle`, which is what keeps the two readers\n // looking at one product instead of two.\n const load =\n readerId === null && api !== null && tokens !== null && roomName !== null\n ? loadGuestMeetingRecord({\n api,\n repository,\n meetingId,\n meeting,\n roomToken: tokens.remembered(roomName),\n })\n : loadMeetingRecord(repository, meetingId, meeting, { userId: readerId });\n void load\n .then((bundle) => {\n if (!live) return;\n setRecordReaderId(readerId);\n setRecord(bundle);\n setLoading(false);\n })\n .catch((thrown: unknown) => {\n if (!live) return;\n // `loadMeetingRecord` converts every per-part refusal into a\n // restriction, so reaching here is a real failure and is stated as one.\n setFailure({\n message: (thrown as Error).message,\n remedy:\n (thrown as { remedy?: string }).remedy ??\n \"The meeting record could not be read. Reload the page; nothing was changed.\",\n });\n setLoading(false);\n });\n return () => {\n live = false;\n };\n }, [repository, meeting, meetingId, readerId, api, tokens, roomName, nonce]);\n\n return {\n loading: loading && failure === null,\n record: recordReaderId === readerId ? record : null,\n failure,\n asking,\n answer,\n coverage,\n askError,\n ask: useCallback(\n async (question: string) => {\n if (ai === null || meetingId === null) return;\n setAsking(true);\n setAskError(null);\n setAnswer(null);\n setCoverage(null);\n try {\n const result = await ai.ask({\n meetingId,\n question,\n onText: (text) => setAnswer(text),\n });\n setAnswer(result.text);\n setCoverage(result.coverage);\n } catch (thrown) {\n // A guest gets the server's own 403 here (\"a guest can read the notes\n // behind the link, but cannot ask the live assistant about a finished\n // meeting. Sign in to do that.\"). It is rendered verbatim.\n setAskError({\n message: (thrown as Error).message,\n remedy:\n (thrown as { remedy?: string }).remedy ??\n \"The assistant could not answer. Nothing was changed by the attempt.\",\n });\n } finally {\n setAsking(false);\n }\n },\n [ai, meetingId],\n ),\n reload: useCallback(() => setNonce((value) => value + 1), []),\n };\n}\n\n/**\n * EVERY MEETING THIS ORGANIZATION HAS, newest first — including the ended ones\n * (MRI-D2). A list that shows only live meetings is a list that empties itself\n * the moment the work is done, and it is what left every wrap-up unreachable.\n */\nexport interface UseMeetingsResult {\n readonly loading: boolean;\n readonly meetings: readonly MeetingRecord[];\n readonly hasMore: boolean;\n readonly failure: { readonly message: string; readonly remedy: string } | null;\n reload: () => void;\n}\n\nexport function useMeetings(limit = 25): UseMeetingsResult {\n const host = useMeetHost();\n const repository = host?.repository ?? null;\n const organizationId = host?.identity.organizationId ?? null;\n const [meetings, setMeetings] = useState<readonly MeetingRecord[]>([]);\n const [hasMore, setHasMore] = useState(false);\n const [loading, setLoading] = useState(true);\n const [failure, setFailure] = useState<{ message: string; remedy: string } | null>(null);\n const [nonce, setNonce] = useState(0);\n\n useEffect(() => {\n if (repository === null || organizationId === null) return undefined;\n let live = true;\n setLoading(true);\n setFailure(null);\n void repository\n .listMeetings({ organizationId, limit })\n .then((page) => {\n if (!live) return;\n setMeetings(page.items);\n setHasMore(page.hasMore);\n setLoading(false);\n })\n .catch((thrown: unknown) => {\n if (!live) return;\n setFailure({\n message: (thrown as Error).message,\n remedy:\n (thrown as { remedy?: string }).remedy ??\n \"The meetings could not be listed. Reload the page; nothing was changed.\",\n });\n setLoading(false);\n });\n return () => {\n live = false;\n };\n }, [repository, organizationId, limit, nonce]);\n\n return {\n loading: loading && failure === null,\n meetings,\n hasMore,\n failure,\n reload: useCallback(() => setNonce((value) => value + 1), []),\n };\n}\n\n\n/* ------------------------------------- what guests may read of this meeting */\n\n/**\n * THE HOST'S CHOICE FOR ONE MEETING (MRF-1).\n *\n * Arman ruled on 2026-09-12 that guest access to the post-meeting record is a\n * configuration and never a question: the system's default, the organization's\n * override, and this — a host deciding for the meeting in front of them,\n * because they are the only person who knows who was in the room and what was\n * said in it.\n *\n * `setting` is what the host chose (`default` means \"use my organization's\");\n * `effective` is what that resolves to RIGHT NOW, which is the only honest way\n * to render \"use my organization's setting\" — a label that does not say what\n * the organization's setting IS makes the host guess.\n *\n * The write is the SERVER's decision and it re-checks host power. This hook\n * never renders a control for a non-host; the component does that, and the\n * server refuses one anyway.\n */\nexport interface UseGuestRecordAccessResult {\n readonly setting: GuestRecordAccessSetting;\n /** Null until the server has said what `default` means for this meeting. */\n readonly effective: GuestRecordAccessResolution | null;\n readonly saving: boolean;\n readonly error: { readonly message: string; readonly remedy: string } | null;\n choose: (setting: GuestRecordAccessSetting) => Promise<void>;\n}\n\nexport function useGuestRecordAccess(\n meeting: MeetingRecord | null,\n): UseGuestRecordAccessResult {\n const host = useMeetHost();\n const api = host?.api ?? null;\n const stored = guestRecordAccessSetting(meeting);\n // The row's own value is the truth until a write of ours succeeds; this is\n // the optimistic half, and it is reset by the row arriving again.\n const [chosen, setChosen] = useState<GuestRecordAccessSetting | null>(null);\n const [effective, setEffective] = useState<GuestRecordAccessResolution | null>(null);\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<{ message: string; remedy: string } | null>(null);\n\n useEffect(() => {\n setChosen(null);\n }, [stored, meeting?.id]);\n\n return {\n setting: chosen ?? stored,\n effective,\n saving,\n error,\n choose: useCallback(\n async (next: GuestRecordAccessSetting) => {\n if (api === null || meeting === null) return;\n setSaving(true);\n setError(null);\n try {\n const result = await setGuestRecordAccess({\n api,\n meetingId: meeting.id,\n organizationId: meeting.organizationId,\n access: next,\n });\n setChosen(result.setting);\n setEffective(result.effective);\n } catch (thrown) {\n // The server's own sentence, rendered. A host who is not a host of\n // this meeting reads why, not a generic failure.\n setError({\n message: (thrown as Error).message,\n remedy:\n (thrown as { remedy?: string }).remedy ??\n \"Nothing was changed. Reload the page and try again.\",\n });\n } finally {\n setSaving(false);\n }\n },\n [api, meeting],\n ),\n };\n}\n","/**\n * THE STAGE — who is big, who is small, and who is not rendered at all.\n *\n * This is pure arithmetic on purpose: layout is the part of a meeting UI that\n * everyone re-derives inside a component and gets subtly wrong, and it is\n * trivially testable once it stops living in JSX.\n *\n * R5 SCALE HONESTY lives here. A 200-person meeting does not render 200 video\n * tiles — every browser dies, and LiveKit's adaptive stream cannot save a\n * layout that asked for 200 subscriptions. The grid PAGES, and the ordering is\n * deliberate rather than \"whatever the roster map iterated\":\n *\n * 1. a screen share (or an explicit pin) owns the stage;\n * 2. then the active speakers, most recent first;\n * 3. then anyone with a hand raised — they are asking to be seen;\n * 4. then cameras on before cameras off (an avatar tile is cheap);\n * 5. then stable by join time, so tiles do not shuffle every time someone\n * breathes. Shuffling tiles is the single most disorienting thing a\n * meeting UI can do.\n */\n\nimport type { MeetParticipant, ParticipantIdentity, StageLayout } from \"./types\";\n\nexport interface StageArgs {\n readonly participants: readonly MeetParticipant[];\n readonly layout: StageLayout;\n readonly pinned: ParticipantIdentity | null;\n readonly activeSpeakers: readonly ParticipantIdentity[];\n /**\n * The participant a HOST spotlighted for everyone (Meet wave 2). A local pin\n * outranks it on this screen; a screen share outranks both.\n */\n readonly spotlight?: ParticipantIdentity | null | undefined;\n /** How many tiles this viewport can honestly render. Default 12. */\n readonly pageSize?: number;\n readonly page?: number;\n}\n\nexport interface Stage {\n /** The large tile, when the layout has one. */\n readonly feature: MeetParticipant | null;\n /** What actually renders as a tile, already paged. */\n readonly tiles: readonly MeetParticipant[];\n /** Everyone not on this page. Rendered as \"+N others\", never dropped silently. */\n readonly overflow: number;\n readonly page: number;\n readonly pageCount: number;\n /** True when a screen share, not a person, is the reason for the big tile. */\n readonly presenting: boolean;\n}\n\nexport const DEFAULT_PAGE_SIZE = 12;\n\nexport function orderParticipants(\n participants: readonly MeetParticipant[],\n activeSpeakers: readonly ParticipantIdentity[],\n): readonly MeetParticipant[] {\n const speakerRank = new Map<ParticipantIdentity, number>();\n activeSpeakers.forEach((identity, index) => speakerRank.set(identity, index));\n\n return [...participants].sort((a, b) => {\n const speakerA = speakerRank.get(a.identity) ?? Number.MAX_SAFE_INTEGER;\n const speakerB = speakerRank.get(b.identity) ?? Number.MAX_SAFE_INTEGER;\n if (speakerA !== speakerB) return speakerA - speakerB;\n if (a.handRaised !== b.handRaised) return a.handRaised ? -1 : 1;\n if (a.cameraEnabled !== b.cameraEnabled) return a.cameraEnabled ? -1 : 1;\n // STABLE from here down. Join time, then identity — never Math.random,\n // never map order, both of which reshuffle the grid on every event.\n if (a.joinedAt !== b.joinedAt) return a.joinedAt < b.joinedAt ? -1 : 1;\n return a.identity < b.identity ? -1 : 1;\n });\n}\n\nexport function computeStage(args: StageArgs): Stage {\n const pageSize = Math.max(1, args.pageSize ?? DEFAULT_PAGE_SIZE);\n const ordered = orderParticipants(args.participants, args.activeSpeakers);\n\n const sharer = ordered.find((participant) => participant.screenSharing) ?? null;\n const pinnedParticipant =\n args.pinned === null\n ? null\n : ordered.find((participant) => participant.identity === args.pinned) ?? null;\n\n // A SCREEN SHARE OUTRANKS A PIN, deliberately: someone presenting is the\n // reason everyone is looking, and a stale pin hiding a live demo is the\n // complaint this rule exists to prevent.\n const spotlit =\n args.spotlight == null\n ? null\n : ordered.find((participant) => participant.identity === args.spotlight) ?? null;\n\n const feature =\n sharer !== null\n ? sharer\n : pinnedParticipant !== null && args.layout !== \"grid\"\n ? pinnedParticipant\n : spotlit !== null\n ? spotlit\n : args.layout === \"grid\"\n ? null\n : ordered[0] ?? null;\n\n const rest =\n feature === null\n ? ordered\n : ordered.filter((participant) => participant.identity !== feature.identity);\n\n const pageCount = Math.max(1, Math.ceil(rest.length / pageSize));\n const page = Math.min(Math.max(0, args.page ?? 0), pageCount - 1);\n const tiles = rest.slice(page * pageSize, page * pageSize + pageSize);\n\n return {\n feature,\n tiles,\n overflow: rest.length - tiles.length,\n page,\n pageCount,\n presenting: sharer !== null,\n };\n}\n\n/** Column count for a grid of N tiles — the shape that keeps tiles squarest. */\nexport function gridColumns(count: number): number {\n if (count <= 1) return 1;\n if (count <= 4) return 2;\n if (count <= 9) return 3;\n if (count <= 16) return 4;\n return 5;\n}\n","/**\n * THE MEETING RECORD — what a meeting IS once the room is gone (MRI-D2).\n *\n * 🚨 THE DEFECT THIS EXISTS TO KILL. Through 2026-09-08 a meeting produced a\n * wrap-up summary, decisions, owner-assigned action items, five windows of live\n * notes, thirty-two transcript segments and a recording — and then had NO\n * SURFACE AT ALL. `/meet/<slug>` fell back to `<PreJoin>` on an ended meeting,\n * so the durable link that R3 promises would outlive the meeting resolved to a\n * screen offering to join a room that no longer exists. Everything the campaign\n * built after the room closed was reachable only from SQL.\n *\n * Three rules hold this file together:\n *\n * 1. **Every read is INDEPENDENT and every refusal is NAMED.** The transcript,\n * the notes, the attendance list and the recording live in four RLS-guarded\n * tables, and a guest holding the link can read NONE of them (only\n * `meet_meeting_by_slug` is granted to `anon`). One `Promise.all` would turn\n * a permission boundary into a blank page. Known guest restrictions never issue private reads; each authenticated read that is refused\n * becomes a `MeetingRecordRestriction` with a sentence — the reader is told\n * what exists and why they cannot see it, which is the difference between a\n * record they can ask for and a product that looks broken.\n * 2. **A partial record is still a record.** A failed transcript read never\n * hides the summary somebody CAN read.\n * 3. **Nothing here computes meaning.** Grouping, ordering and formatting only.\n * The summary, decisions and action items are durable rows written by the\n * wrap-up mandate (D5/D18); this module never re-derives them from the\n * transcript, because two sources for one fact is how they start to disagree.\n */\n\nimport { formatDurationMs } from \"@ai-matrx/kit/format\";\nimport type { MeetApi } from \"./api\";\nimport { MeetError } from \"./errors\";\nimport { displayNameFor, learnNames, type NameBook } from \"./names\";\nimport type { MeetRepository } from \"./repository\";\nimport { MEET_ROUTES, ROOM_TOKEN_HEADER, type RoomToken } from \"./tokens\";\nimport type {\n MeetingAttendee,\n MeetingId,\n MeetingNote,\n MeetIdentity,\n MeetingRecord,\n OrganizationId,\n ParticipantIdentity,\n RecordingRecord,\n TranscriptSegment,\n} from \"./types\";\n\n/** One thing the reader could not see, and the honest reason. Never a blank. */\nexport interface MeetingRecordRestriction {\n /** Which part of the record: `transcript`, `notes`, `attendance`, `recording`. */\n readonly part: \"transcript\" | \"notes\" | \"attendance\" | \"recording\";\n readonly message: string;\n readonly remedy: string;\n}\n\n/** One visible access state, made from restrictions that share one remedy. */\nexport interface MeetingRecordRestrictionNotice {\n readonly parts: readonly MeetingRecordRestriction[\"part\"][];\n readonly message: string;\n readonly remedy: string;\n}\n\n/** A run of consecutive lines by one speaker — how a person reads a transcript. */\nexport interface TranscriptBlock {\n readonly id: string;\n /** Who spoke. Blocks break on THIS, never on the rendered name (MRI-A16). */\n readonly identity: ParticipantIdentity;\n readonly speaker: string;\n /** ISO of the first line in the block. */\n readonly startedAt: string;\n readonly lines: readonly TranscriptSegment[];\n}\n\nexport interface MeetingRecordBundle {\n readonly meeting: MeetingRecord;\n readonly attendees: readonly MeetingAttendee[];\n /** The wrap-up summary: `kind='note'` with `metadata.role='summary'` (D5). */\n readonly summary: MeetingNote | null;\n /** D20: the AUTHORITATIVE set — window rows the wrap-up superseded are out. */\n readonly decisions: readonly MeetingNote[];\n readonly actionItems: readonly MeetingNote[];\n /** The live-notes windows, in window order (D3). */\n readonly liveNotes: readonly MeetingNote[];\n readonly transcript: readonly TranscriptSegment[];\n /** The most recent recording attempt, whatever state it reached. */\n readonly recording: RecordingRecord | null;\n /** What this reader could NOT see. Rendered; never swallowed. */\n readonly restrictions: readonly MeetingRecordRestriction[];\n /**\n * Identity → name, learned from everything this read COULD see: the durable\n * attendance rows and the transcript's own `speaker` column. It is what stops\n * a raw LiveKit token reaching the screen when one of those reads was refused\n * (MRI-A16).\n */\n readonly names: NameBook;\n}\n\n/**\n * The current wrap-up summary. Repairs preserve the prior durable row for\n * history, then mark it `superseded_by`; every current-facing projection must\n * therefore make the same distinction as decisions and action items.\n */\nexport function activeWrapUpSummary(notes: readonly MeetingNote[]): MeetingNote | null {\n return notes.find((note) => note.role === \"summary\" && note.supersededBy === null) ?? null;\n}\n\n/**\n * The sentence a reader gets when the database refuses them a part of the\n * record. It is deliberately about TENANCY, not about them: `meet_notes`,\n * `meet_transcript_segments`, `meet_participants` and `meet_recordings` have no\n * `anon` policy at all, so a link-follower with no session reaches exactly the\n * meeting row and nothing else. That is the correct posture and it must be\n * SAID, not rendered as emptiness.\n */\nconst RESTRICTION_REMEDY =\n \"The people in this meeting's organization can read it. Sign in with an account in that \" +\n \"organization — following the link is enough to join a meeting, but not to read its record.\";\n\nconst PART_LABEL: Readonly<Record<MeetingRecordRestriction[\"part\"], string>> = {\n transcript: \"The transcript of this meeting is not readable from this account.\",\n notes: \"The notes, decisions and action items are not readable from this account.\",\n attendance: \"Who attended is not readable from this account.\",\n recording: \"The recording is not readable from this account.\",\n};\n\n/** A refusal is DATA. A transport wobble is not, and is re-thrown as itself. */\nfunction restrictionFor(\n part: MeetingRecordRestriction[\"part\"],\n error: unknown,\n): MeetingRecordRestriction {\n const code = (error as { code?: string }).code;\n const denied =\n code === \"forbidden\" || code === \"session-unavailable\" || code === \"not-found\";\n return {\n part,\n message: denied\n ? PART_LABEL[part]\n : `${PART_LABEL[part]} (${(error as Error).message ?? \"the read failed\"})`,\n remedy: denied\n ? RESTRICTION_REMEDY\n : (error as { remedy?: string }).remedy ??\n \"This is a transient read failure, not a permission decision. Reload the page.\",\n };\n}\n\n/**\n * Load the record parts the reader may request; state all restrictions.\n *\n * `meeting` is passed in when the caller already resolved it (the slug route\n * does, through the `anon`-granted RPC) — re-reading it through the table would\n * fail for exactly the reader who most needs the page to work.\n */\nexport async function loadMeetingRecord(\n repository: MeetRepository,\n meetingId: MeetingId,\n meeting: MeetingRecord,\n reader: Pick<MeetIdentity, \"userId\"> = { userId: null },\n): Promise<MeetingRecordBundle> {\n const restrictions: MeetingRecordRestriction[] = [];\n\n async function attempt<T>(\n part: MeetingRecordRestriction[\"part\"],\n run: () => Promise<T>,\n empty: T,\n ): Promise<T> {\n // No anonymous policy exists for these four tables. State the known\n // restriction without probing private data or generating expected 401s.\n if (reader.userId === null) {\n restrictions.push(restrictionFor(part, { code: \"session-unavailable\" }));\n return empty;\n }\n try {\n return await run();\n } catch (error) {\n restrictions.push(restrictionFor(part, error));\n return empty;\n }\n }\n\n // Four independent reads, four independent verdicts. Deliberately NOT\n // `Promise.all` over a single try/catch — see rule 1 in the header.\n const [attendees, notes, transcript, recordings] = await Promise.all([\n attempt<readonly MeetingAttendee[]>(\"attendance\", () => repository.attendees(meetingId), []),\n attempt<readonly MeetingNote[]>(\"notes\", () => repository.notes(meetingId), []),\n attempt<readonly TranscriptSegment[]>(\n \"transcript\",\n () => repository.transcript(meetingId),\n [],\n ),\n attempt<readonly RecordingRecord[]>(\n \"recording\",\n () => repository.recordings(meetingId),\n [],\n ),\n ]);\n\n return {\n meeting,\n attendees,\n summary: activeWrapUpSummary(notes),\n // 🚨 D20: THE WRAP-UP IS THE AUTHORITATIVE POST-MEETING SET. A window row the\n // wrap-up superseded is still in `notes` and still in the timeline below —\n // it is simply not listed a second time as a decision that was made.\n decisions: notes.filter((note) => note.kind === \"decision\" && note.supersededBy === null),\n actionItems: notes.filter(\n (note) => note.kind === \"action-item\" && note.supersededBy === null,\n ),\n liveNotes: notes\n .filter((note) => note.kind === \"note\" && note.role === null)\n // Window order, then creation order for the notes of one window.\n .slice()\n .sort((left, right) => {\n const a = left.window ?? Number.MAX_SAFE_INTEGER;\n const b = right.window ?? Number.MAX_SAFE_INTEGER;\n return a === b ? left.createdAt.localeCompare(right.createdAt) : a - b;\n }),\n transcript,\n // `recordings` is newest first; the record shows the latest attempt,\n // including a failed one — a recording that failed is a fact the reader\n // needs, not a row to hide.\n recording: recordings[0] ?? null,\n restrictions,\n names: learnNames(learnNames({}, attendees), transcript.map((line) => ({\n identity: line.identity,\n displayName: line.speaker,\n }))),\n };\n}\n\n/**\n * 🚨 **A READ THAT WAS REFUSED IS NOT AN EMPTY RESULT (MRI-A16).**\n *\n * On production 2026-09-09 a guest's record view said *\"No wrap-up was written\n * for this meeting\"* directly underneath a panel that had just told them, in\n * the same screen, that the notes are not readable from their account — and\n * *\"Nothing was recorded as a decision\"* beside a decision that exists\n * (MRI-C8). The page asserted an absence it had no way to know, which is worse\n * than saying nothing: a person who reads \"no wrap-up was written\" stops\n * looking for one.\n *\n * So no surface writes its own empty sentence any more. It asks here, and gets\n * either its absence sentence — earned, because the read SUCCEEDED and returned\n * nothing — or the refusal, said plainly.\n */\nexport const REFUSED_ABSENCE = \"This record is not shared with guests.\";\n\n/** Was this part of the record refused to this reader? */\nexport function wasRefused(\n bundle: MeetingRecordBundle,\n part: MeetingRecordRestriction[\"part\"],\n): boolean {\n return bundle.restrictions.some((restriction) => restriction.part === part);\n}\n\n/**\n * The sentence to show where a part of the record has nothing in it. NEVER an\n * absence claim over a read that was refused.\n */\nexport function absenceSentence(\n bundle: MeetingRecordBundle,\n part: MeetingRecordRestriction[\"part\"],\n absence: string,\n): string {\n return wasRefused(bundle, part) ? REFUSED_ABSENCE : absence;\n}\n\n/**\n * 🚨 **\"NO WRAP-UP WAS WRITTEN\" IS A CLAIM, AND FOR ~33 SECONDS IT WAS FALSE.**\n *\n * On production 2026-09-09 the HOST's record view said *\"No wrap-up was written\n * for this meeting\"* between 04:46:42 — the flip from the room to the record —\n * and 04:47:15, when the wrap-up landed. The read was permitted and genuinely\n * empty, so this is not the refusal class above; it is the OTHER way a screen\n * lies, by reading \"not here yet\" as \"never happened\". A person who reads *\"no\n * wrap-up was written\"* closes the tab.\n *\n * The meeting row already knows the difference, and it is not a guess: the\n * wrap-up is a durable job, `enqueue_wrap_up` stamps\n * `metadata.note_taker.intelligence.wrap_up` when it queues it, and the graph\n * action stamps `state: \"failed\"` when the pass refuses TERMINALLY. So:\n *\n * - a summary exists → `written`;\n * - the notes read was refused → `refused` (never an absence claim);\n * - the job is marked failed → `failed`, in the server's own words;\n * - the job is queued or running → `in-progress`, with a refresh affordance;\n * - nothing ever queued one → `absent`, which is the only EARNED absence.\n *\n * There is no timeout that flips `in-progress` into `absent`. A wrap-up that is\n * genuinely stuck says it is still being written — which is TRUE — rather than\n * inventing a verdict this browser has no way to reach.\n */\nexport type WrapUpStatus =\n | { readonly state: \"written\" }\n | { readonly state: \"in-progress\"; readonly message: string; readonly canRefresh: true }\n | { readonly state: \"failed\"; readonly message: string }\n | { readonly state: \"refused\"; readonly message: string }\n | { readonly state: \"absent\"; readonly message: string };\n\n/** What `metadata.note_taker` holds, as far as this file cares. */\nfunction noteTakerMetadata(meeting: MeetingRecord): Record<string, unknown> {\n const raw = (meeting.metadata as Record<string, unknown>)[\"note_taker\"];\n return typeof raw === \"object\" && raw !== null && !Array.isArray(raw)\n ? (raw as Record<string, unknown>)\n : {};\n}\n\nconst WRAP_UP_IN_PROGRESS =\n \"The wrap-up is being written… The summary, the decisions and the action items are \" +\n \"produced from the whole transcript once the meeting ends, which takes a moment longer \" +\n \"than the meeting does.\";\n\nconst WRAP_UP_ABSENT =\n \"No wrap-up was written for this meeting. A summary is produced from the transcript \" +\n \"when the meeting ends and the note-taker was in the room.\";\n\n/** Where the wrap-up actually is. Never \"absent\" over a job that is running. */\nexport function wrapUpStatus(bundle: MeetingRecordBundle): WrapUpStatus {\n if (bundle.summary !== null) return { state: \"written\" };\n if (wasRefused(bundle, \"notes\")) return { state: \"refused\", message: REFUSED_ABSENCE };\n\n const noteTaker = noteTakerMetadata(bundle.meeting);\n const intelligenceRaw = noteTaker[\"intelligence\"];\n const intelligence: Record<string, unknown> =\n typeof intelligenceRaw === \"object\" && intelligenceRaw !== null && !Array.isArray(intelligenceRaw)\n ? (intelligenceRaw as Record<string, unknown>)\n : {};\n const wrapUpRaw = intelligence[\"wrap_up\"];\n const wrapUp: Record<string, unknown> =\n typeof wrapUpRaw === \"object\" && wrapUpRaw !== null && !Array.isArray(wrapUpRaw)\n ? (wrapUpRaw as Record<string, unknown>)\n : {};\n\n if (wrapUp[\"state\"] === \"failed\") {\n const reason = wrapUp[\"reason\"];\n return {\n state: \"failed\",\n // THE SERVER'S OWN SENTENCE, verbatim. It already names the remedy, and a\n // house sentence over it would hide the one thing worth reading.\n message:\n typeof reason === \"string\" && reason.trim().length > 0\n ? reason.trim()\n : \"The wrap-up pass failed and no summary was written. It is not retried \" +\n \"automatically; a host can end the meeting again to re-queue it.\",\n };\n }\n\n const queued =\n typeof wrapUp[\"run_id\"] === \"string\" ||\n typeof intelligence[\"wrap_up_run_id\"] === \"string\" ||\n wrapUp[\"state\"] === \"queued\" ||\n wrapUp[\"state\"] === \"running\";\n // A meeting the note-taker actually attended will get a wrap-up even if this\n // browser loaded the record before the enqueue stamp landed — that race is\n // the whole defect, so `ended + the note-taker was there` is enough.\n const attended =\n noteTaker[\"state\"] === \"ended\" ||\n noteTaker[\"state\"] === \"transcribing\" ||\n noteTaker[\"state\"] === \"handoff_pending\";\n\n if (hasEnded(bundle.meeting) && (queued || attended)) {\n return { state: \"in-progress\", message: WRAP_UP_IN_PROGRESS, canRefresh: true };\n }\n return { state: \"absent\", message: WRAP_UP_ABSENT };\n}\n\n/**\n * GROUP THE TRANSCRIPT THE WAY A PERSON READS IT: consecutive lines by one\n * speaker become one block with one timestamp. Reading thirty-two rows each\n * re-stamped with a name and a clock is how a transcript becomes unreadable.\n */\nexport function groupTranscript(\n segments: readonly TranscriptSegment[],\n names: NameBook = {},\n): readonly TranscriptBlock[] {\n const blocks: TranscriptBlock[] = [];\n for (const segment of segments) {\n const last = blocks[blocks.length - 1];\n // 🚨 GROUPED BY IDENTITY, not by the rendered name (MRI-A16). Two people\n // whose names nobody ever learned both render \"Unnamed guest\", and merging\n // their lines into one block would put words in the wrong mouth — the exact\n // failure the honest placeholder exists to avoid.\n if (last !== undefined && last.identity === segment.identity) {\n blocks[blocks.length - 1] = { ...last, lines: [...last.lines, segment] };\n continue;\n }\n blocks.push({\n id: segment.id,\n identity: segment.identity,\n // One resolution, shared with the live rail — so the record and the room\n // can never disagree about who said something.\n speaker: displayNameFor(names, segment.identity, segment.speaker),\n startedAt: segment.startedAt,\n lines: [segment],\n });\n }\n return blocks;\n}\n\n/**\n * WHAT THE RECORDING IS DOING, in a sentence — including the two states people\n * hit most and understand least. `processing` is not \"broken\" and `failed` is\n * never silence: both say what happened and what to do.\n */\nexport function recordingNotice(recording: RecordingRecord | null): string | null {\n if (recording === null) return null;\n switch (recording.state) {\n case \"available\":\n if (recording.retention?.phase !== \"warning\") return null;\n return `This recording expires on ${retentionDueDate(recording.retention.dueAt)}. The transcript and notes remain available.`;\n case \"expired\":\n return \"This recording has expired. The transcript and notes remain available.\";\n case \"processing\":\n case \"stopping\":\n return \"The recording is still being processed. It appears here on its own once the file lands — nothing is lost while it is being written.\";\n case \"recording\":\n case \"starting\":\n return \"This recording is still being written. It becomes playable once the meeting's egress finishes.\";\n case \"failed\":\n return recording.failureReason !== null && recording.failureReason.length > 0\n ? `The recording failed: ${recording.failureReason}`\n : \"The recording failed and no file was produced. The transcript below was written separately and is unaffected.\";\n default:\n return null;\n }\n}\n\nfunction retentionDueDate(value: string): string {\n const dueAt = new Date(value);\n return Number.isNaN(dueAt.getTime()) ? \"its scheduled retention date\" : dueAt.toLocaleString();\n}\n\n/** Only an `available` recording has a file to play. Nothing else pretends to. */\nexport function playableRecordingFileId(recording: RecordingRecord | null): string | null {\n if (recording === null) return null;\n return recording.state === \"available\" ? recording.fileId : null;\n}\n\n/**\n * A MEETING IS OVER WHEN THE SERVER SAYS SO. `ended_at` is stamped by\n * `POST /v1/meet/end` or by the auto-end evaluation (MRI-A6) — never by a\n * client noticing the room is empty.\n */\nexport function hasEnded(meeting: MeetingRecord | null): boolean {\n return meeting !== null && meeting.endedAt !== null;\n}\n\n/**\n * \"Thursday, 8 September 2026, 4:21 PM · 19 minutes\". One shape everywhere.\n *\n * THE SPAN IS `formatDurationMs`'s (2026-09-12). This body used to divide by\n * `60_000` and pluralise \"minute\" itself — a duration formatter living in a\n * PACKAGE, found the day `aidream/apps/shared` became a scan root. `@ai-matrx/\n * meet` already depends on `@ai-matrx/kit`, and `style: \"long\"` is precisely\n * this voice (\"19 minutes\", \"1 minute\"). Three things improve by adopting it:\n * a 40-second meeting read \"0 minutes\" and now reads \"40 seconds\" (the\n * confident zero the package refuses), a 19-minute-35-second meeting read\n * \"20 minutes\" and now reads \"19 minutes\" (prose asserts at-least, so it\n * floors), and a 90-minute meeting reads \"1 hour\" instead of \"90 minutes\".\n */\nexport function meetingWhen(meeting: MeetingRecord, locale?: string): string {\n const start = meeting.startedAt ?? meeting.scheduledFor;\n if (start === null) return \"Time not recorded\";\n const startedAt = new Date(start);\n if (Number.isNaN(startedAt.getTime())) return \"Time not recorded\";\n const when = startedAt.toLocaleString(locale, {\n weekday: \"long\",\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n if (meeting.endedAt === null || meeting.startedAt === null) return when;\n const endedAt = new Date(meeting.endedAt);\n if (Number.isNaN(endedAt.getTime())) return when;\n const elapsedMs = endedAt.getTime() - startedAt.getTime();\n return `${when} · ${formatDurationMs(elapsedMs, { style: \"long\" })}`;\n}\n\n/* ═══════════════════════════════════════════════════════════════════════════\n * MRF-1 — WHAT A GUEST MAY READ, AND HOW THEY READ IT\n *\n * 🚨 THE DEFECT THIS CLOSES. Everything above this line is correct and was\n * still the wrong product: a guest who attended a meeting, was admitted by the\n * host, spoke, and was transcribed got FOUR refusal sentences where the record\n * should have been. `anon` has no grant on the four org-scoped tables and\n * widening it is forbidden (MRI-A10) — a meeting link is not organization\n * membership — so the honest refusals were the only thing this file could say.\n *\n * Arman ruled on 2026-09-12 that guest access to the record is a CONFIGURATION\n * and never a question: a system default, an organization override, and a\n * per-meeting setting a host chooses. The server resolves it and serves the\n * shared subset at `GET /api/v1/meet/record`, authorized by the room token this\n * device already holds. So this half does three things and no more:\n *\n * 1. reads that route and turns its answer into the SAME `MeetingRecordBundle`\n * the member lane produces — so one screen renders both readers and they can\n * never drift into two products;\n * 2. states every part the level does NOT share as a `MeetingRecordRestriction`\n * with the server's own sentence, which is what keeps \"not shared\" and\n * \"nothing happened\" different things on screen;\n * 3. gives a host the control that sets it.\n *\n * What it does NOT do is decide anything. The level, the refusals and the\n * remedies are the server's words; a client that computed its own would be a\n * second authority on who may read a transcript.\n * ═══════════════════════════════════════════════════════════════════════════ */\n\n\n/** How much of a finished meeting a GUEST may read. Pinned with the server. */\nexport type GuestRecordAccess = \"none\" | \"summary\" | \"full\";\n\n/** Widest last. The ORDER is the comparison, exactly as it is on the server. */\nexport const GUEST_RECORD_ACCESS_LEVELS: readonly GuestRecordAccess[] = [\n \"none\",\n \"summary\",\n \"full\",\n];\n\n/**\n * What a HOST may choose for one meeting. `default` is not a fourth level — it\n * is the absence of a per-meeting choice, and it is the only way to un-choose.\n */\nexport type GuestRecordAccessSetting = \"default\" | GuestRecordAccess;\n\nexport const GUEST_RECORD_ACCESS_CHOICES: readonly GuestRecordAccessSetting[] = [\n \"default\",\n \"summary\",\n \"full\",\n \"none\",\n];\n\n/** `meet_meetings.metadata.guest_record_access`. No DDL; a setting on a row. */\nexport const GUEST_RECORD_ACCESS_METADATA_KEY = \"guest_record_access\";\n\n/** What a host chose for THIS meeting, read from the row they already have. */\nexport function guestRecordAccessSetting(\n meeting: MeetingRecord | null,\n): GuestRecordAccessSetting {\n const raw = (meeting?.metadata as Record<string, unknown> | undefined)?.[\n GUEST_RECORD_ACCESS_METADATA_KEY\n ];\n return GUEST_RECORD_ACCESS_LEVELS.includes(raw as GuestRecordAccess)\n ? (raw as GuestRecordAccess)\n : \"default\";\n}\n\n/** The sentence on the host's control. Plain English, never a token. */\nexport function guestRecordAccessLabel(setting: GuestRecordAccessSetting): string {\n switch (setting) {\n case \"default\":\n return \"Use my organization's setting\";\n case \"summary\":\n return \"Summary, decisions and action items\";\n case \"full\":\n return \"Everything, including the transcript\";\n case \"none\":\n return \"Nothing — keep the record internal\";\n }\n}\n\n/** What each choice actually means for the people who were in the room. */\nexport function guestRecordAccessExplanation(setting: GuestRecordAccessSetting): string {\n switch (setting) {\n case \"default\":\n return \"Guests who attended read whatever your organization shares by default. An administrator sets that once, for every meeting nobody thinks about.\";\n case \"summary\":\n return \"Guests who attended read the wrap-up summary, the decisions, the action items, the notes taken as it happened, and who was here. They do not get the word-for-word transcript or the recording.\";\n case \"full\":\n return \"Guests who attended read everything this meeting produced, including the word-for-word transcript of what each person said.\";\n case \"none\":\n return \"Guests who attended are told plainly that this meeting's record is kept inside your organization. They see nothing of it.\";\n }\n}\n\n/** What came back from the server, so a surface never has to infer a level. */\nexport interface GuestRecordAccessResolution {\n readonly level: GuestRecordAccess;\n /** `meeting` when a host chose for this one; `organization` otherwise. */\n readonly source: \"meeting\" | \"organization\";\n}\n\n/** What the parts of the record the level does not share are called, and why. */\nconst NOT_SHARED: Readonly<Record<MeetingRecordRestriction[\"part\"], string>> = {\n transcript:\n \"The word-for-word transcript of this meeting is not shared with guests.\",\n notes: \"The notes, decisions and action items are not shared with guests.\",\n attendance: \"Who attended is not shared with guests.\",\n recording: \"The recording of this meeting is not shared with guests.\",\n};\n\nconst NOT_SHARED_REMEDY =\n \"The organization that held this meeting decided how much of its record guests can read. \" +\n \"If you need more, ask whoever invited you — they can send it to you, or change the \" +\n \"setting for this meeting.\";\n\nconst RESTRICTION_PART_NAME: Readonly<Record<MeetingRecordRestriction[\"part\"], string>> = {\n attendance: \"attendance\",\n notes: \"notes and decisions\",\n transcript: \"word-for-word transcript\",\n recording: \"recording\",\n};\n\nfunction joinPartNames(parts: readonly MeetingRecordRestriction[\"part\"][]): string {\n const names = parts.map((part) => RESTRICTION_PART_NAME[part]);\n if (names.length < 2) return names[0] ?? \"this part of the record\";\n if (names.length === 2) return `${names[0]} and ${names[1]}`;\n return `${names.slice(0, -1).join(\", \")}, and ${names[names.length - 1]}`;\n}\n\n/**\n * Repeated policy refusals are one access state, not four alarming cards.\n *\n * The individual rows remain durable data for absence handling in their own\n * sections. This projection groups only rows with the exact same remedy, so a\n * distinct transport or integrity failure remains visible on its own.\n */\nexport function summarizeMeetingRecordRestrictions(\n restrictions: readonly MeetingRecordRestriction[],\n): readonly MeetingRecordRestrictionNotice[] {\n const grouped = new Map<string, MeetingRecordRestriction[]>();\n for (const restriction of restrictions) {\n const rows = grouped.get(restriction.remedy) ?? [];\n rows.push(restriction);\n grouped.set(restriction.remedy, rows);\n }\n return [...grouped.values()].map((rows) => {\n if (rows.length === 1) {\n const row = rows[0]!;\n return { parts: [row.part], message: row.message, remedy: row.remedy };\n }\n return {\n parts: rows.map((row) => row.part),\n message: `Some parts of this meeting record are not available to this reader: ${joinPartNames(rows.map((row) => row.part))}.`,\n remedy: rows[0]!.remedy,\n };\n });\n}\n\n/**\n * Read the record the server shares with THIS guest.\n *\n * `roomToken` is the pass this device kept from the meeting\n * (`TokenClient.remembered`). It is presented in a header, never appended to\n * the URL. A guest with no pass, an expired pass, or a level of `none` gets the\n * server's refusal — as restrictions on a real bundle, so the screen says what\n * it cannot show instead of collapsing into an error page.\n */\nexport async function loadGuestMeetingRecord(args: {\n api: MeetApi;\n repository: MeetRepository;\n meetingId: MeetingId;\n meeting: MeetingRecord;\n roomToken: RoomToken | null;\n}): Promise<MeetingRecordBundle> {\n const { api, repository, meetingId, meeting, roomToken } = args;\n\n if (roomToken === null) {\n // NOT A GUESS AND NOT A FETCH. This browser has no pass for this meeting,\n // which the server would answer with the same sentence — asking it first\n // would only add a round trip and a 403 in the console.\n return refusedBundle(\n meeting,\n \"This meeting's record is only readable by the people who were in it.\",\n \"Open the meeting from the link you were invited with, in the same browser you used \" +\n \"to attend — that is what identifies you to this meeting. Signing in with an \" +\n \"account in the organization that held the meeting also works.\",\n );\n }\n\n let response: Response;\n try {\n response = await api.request({\n path: `${MEET_ROUTES.record}?meeting_id=${encodeURIComponent(meetingId)}`,\n method: \"GET\",\n // A GUEST HAS NO SESSION AND IS STILL A FIRST-CLASS READER (D6).\n requireAuth: false,\n operation: \"meet.record\",\n headers: { [ROOM_TOKEN_HEADER]: roomToken.token },\n });\n } catch (error) {\n // A transport wobble is not a permission decision and must not read as one.\n return refusedBundle(\n meeting,\n `This meeting's record could not be read (${(error as Error).message}).`,\n (error as { remedy?: string }).remedy ??\n \"This is a connection failure, not a decision about you. Reload the page.\",\n );\n }\n\n if (!response.ok) {\n const refusal = await readRefusal(response);\n return refusedBundle(meeting, refusal.message, refusal.remedy);\n }\n\n const body = (await response.json()) as Record<string, unknown>;\n const payload = (\n typeof body[\"data\"] === \"object\" && body[\"data\"] !== null ? body[\"data\"] : body\n ) as GuestRecordPayload;\n\n const rows = (key: keyof GuestRecordPayload): Record<string, unknown>[] =>\n Array.isArray(payload[key]) ? (payload[key] as Record<string, unknown>[]) : [];\n\n const attendees = rows(\"attendees\").map((row) => repository.projectAttendee(row));\n const notes = rows(\"notes\").map((row) => repository.projectNote(row));\n const transcript = rows(\"transcript\").map((row) => repository.projectSegment(row));\n const recordings = rows(\"recordings\").map((row) => repository.projectRecording(row));\n\n // 🚨 THE RESTRICTIONS COME FROM `shared`, NOT FROM AN EMPTY ARRAY. A level of\n // `summary` and a meeting where nobody spoke both produce zero transcript\n // rows, and telling the reader they are the same thing is the MRI-A16 defect.\n const shared = (payload.shared ?? {}) as Record<string, boolean>;\n const restrictions: MeetingRecordRestriction[] = [];\n for (const part of [\"attendance\", \"notes\", \"transcript\", \"recording\"] as const) {\n if (shared[part] === false) {\n restrictions.push({ part, message: NOT_SHARED[part], remedy: NOT_SHARED_REMEDY });\n }\n }\n\n return {\n meeting,\n attendees,\n summary: activeWrapUpSummary(notes),\n decisions: notes.filter((note) => note.kind === \"decision\" && note.supersededBy === null),\n actionItems: notes.filter(\n (note) => note.kind === \"action-item\" && note.supersededBy === null,\n ),\n liveNotes: notes\n .filter((note) => note.kind === \"note\" && note.role === null)\n .slice()\n .sort((left, right) => {\n const a = left.window ?? Number.MAX_SAFE_INTEGER;\n const b = right.window ?? Number.MAX_SAFE_INTEGER;\n return a === b ? left.createdAt.localeCompare(right.createdAt) : a - b;\n }),\n transcript,\n recording: recordings[0] ?? null,\n restrictions,\n names: learnNames(\n learnNames({}, attendees),\n transcript.map((line) => ({ identity: line.identity, displayName: line.speaker })),\n ),\n };\n}\n\n/** The row shapes the route returns — the same snake_case the tables use. */\ninterface GuestRecordPayload {\n readonly access?: GuestRecordAccess;\n readonly access_source?: \"meeting\" | \"organization\";\n readonly shared?: Record<string, boolean>;\n readonly attendees?: unknown;\n readonly notes?: unknown;\n readonly transcript?: unknown;\n readonly recordings?: unknown;\n readonly recording_notice?: string;\n}\n\n/**\n * THE SERVER'S OWN WORDS, verbatim. Every meet refusal carries\n * `{message, remedy}`, and a house sentence written over it would hide the one\n * thing worth reading — including the difference between \"your pass expired,\n * open the link again\" and \"this record is not shared with guests\".\n */\nasync function readRefusal(\n response: Response,\n): Promise<{ message: string; remedy: string }> {\n try {\n const body = (await response.json()) as Record<string, unknown>;\n const detail = (\n typeof body[\"detail\"] === \"object\" && body[\"detail\"] !== null ? body[\"detail\"] : body\n ) as Record<string, unknown>;\n const message = detail[\"message\"];\n const remedy = detail[\"remedy\"];\n if (typeof message === \"string\" && message.length > 0) {\n return {\n message,\n remedy:\n typeof remedy === \"string\" && remedy.length > 0\n ? remedy\n : \"Ask whoever hosted the meeting for what you need.\",\n };\n }\n } catch {\n /* falls through to the status sentence below */\n }\n return {\n message: `This meeting's record could not be read (the server answered ${response.status}).`,\n remedy:\n \"This is not a decision about you — it is a failure to reach the record. Reload the \" +\n \"page; if it repeats, tell whoever hosted the meeting.\",\n };\n}\n\n/** A real bundle whose every part is refused, with ONE reason said once. */\nfunction refusedBundle(\n meeting: MeetingRecord,\n message: string,\n remedy: string,\n): MeetingRecordBundle {\n return {\n meeting,\n attendees: [],\n summary: null,\n decisions: [],\n actionItems: [],\n liveNotes: [],\n transcript: [],\n recording: null,\n // Every empty collection below is a refusal, never evidence of absence.\n // The record renderer asks its own part before it writes an empty-state\n // sentence, so omitting attendance here made a denied roster read as\n // “Nobody attended.” `summarizeMeetingRecordRestrictions` still presents\n // this shared server reason once at the top of the record.\n restrictions: ([\"attendance\", \"notes\", \"transcript\", \"recording\"] as const).map(\n (part) => ({ part, message, remedy }),\n ),\n names: {},\n };\n}\n\n/**\n * A HOST chooses what guests may read of THIS meeting.\n *\n * Host power is the SERVER's decision and it re-checks it; this function exists\n * so the control has one call to make, and it returns what the choice RESOLVES\n * to so the screen never has to guess what \"my organization's setting\" means\n * today.\n */\nexport async function setGuestRecordAccess(args: {\n api: MeetApi;\n meetingId: MeetingId;\n organizationId: OrganizationId;\n access: GuestRecordAccessSetting;\n}): Promise<{\n readonly setting: GuestRecordAccessSetting;\n readonly effective: GuestRecordAccessResolution;\n}> {\n const response = await args.api.request({\n path: MEET_ROUTES.recordAccess,\n method: \"POST\",\n requireAuth: true,\n operation: \"meet.record.access\",\n body: {\n meeting_id: args.meetingId,\n organization_id: args.organizationId,\n access: args.access,\n },\n });\n if (!response.ok) {\n const refusal = await readRefusal(response);\n throw new MeetError(\"forbidden\", refusal.message, refusal.remedy);\n }\n const body = (await response.json()) as Record<string, unknown>;\n const payload = (\n typeof body[\"data\"] === \"object\" && body[\"data\"] !== null ? body[\"data\"] : body\n ) as {\n setting?: GuestRecordAccessSetting;\n effective?: GuestRecordAccessResolution;\n };\n return {\n setting: payload.setting ?? args.access,\n effective: payload.effective ?? { level: \"summary\", source: \"organization\" },\n };\n}\n\n/** What a guest is told when the level shares nothing. Rendered, never hidden. */\nexport const GUEST_RECORD_NOT_SHARED = NOT_SHARED;\n","\"use client\";\n\n/**\n * THE PRODUCT UI (R6/R7). Not a headless kernel with a note telling the host to\n * build the rest — the whole meeting surface ships here, because per THE\n * ALL-INCLUSIVE LAW a package that withholds its components withholds its\n * product.\n *\n * The bar: FaceTime and Zoom raised by Apple's design team. Concretely, and\n * every one of these is enforced by the stylesheet or the canary:\n *\n * - `dvh`, never `vh` — iOS Safari's `vh` includes the collapsing toolbar, so a\n * `100vh` stage puts the control bar under the browser chrome.\n * - Safe-area insets on the control bar, so the hang-up button is not under the\n * home indicator.\n * - 44px touch targets, and 16px input text (anything smaller zooms iOS Safari\n * on focus, which in a meeting looks like the app broke).\n * - Semantic tokens only. There is not one hardcoded color in the package.\n * - Real loading states and no dead ends: a control the actor cannot use is\n * ABSENT, never disabled-looking, and never a button that will be refused.\n */\n\nimport { useEffect, useLayoutEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport { ErrorBox } from \"@ai-matrx/design-system\";\nimport { avatarPaletteIndex, formatDurationMs, getInitials } from \"@ai-matrx/kit/format\";\nimport { fileDownloadPath, type MeetFileMedia } from \"../core/api\";\nimport { displayNameFor } from \"../core/names\";\nimport { participantSummary } from \"../core/format\";\nimport { gridColumns } from \"../core/layout\";\nimport { meetingLink } from \"../core/meetings\";\nimport { asMeetingId } from \"../core/types\";\nimport type {\n CallInvite,\n CallMode,\n CallablePerson,\n MeetParticipant,\n MeetingKind,\n MeetingRecord,\n ParticipantIdentity,\n ParticipantRole,\n RoomName,\n} from \"../core/types\";\nimport {\n CameraIcon,\n CameraOffIcon,\n ChatIcon,\n CheckIcon,\n CloseIcon,\n HandIcon,\n LockIcon,\n MicIcon,\n MicOffIcon,\n PeopleIcon,\n PhoneIcon,\n PhoneOffIcon,\n PinIcon,\n RecordIcon,\n ScreenShareIcon,\n SettingsIcon,\n SignalIcon,\n SmileIcon,\n SpeakerIcon,\n SpotlightIcon,\n SparklesIcon,\n KeyboardIcon,\n FlagIcon,\n PencilIcon,\n MoreIcon,\n SearchIcon,\n WifiLowIcon,\n} from \"./icons\";\nimport {\n useCalls,\n useCanModerate,\n useConsentNotice,\n useElapsed,\n useEndMeeting,\n useHostControls,\n useLobby,\n useLocalMedia,\n useMeetAi,\n useGuestRecordAccess,\n useMeetingRecord,\n useMeetings,\n useRecording,\n useRoom,\n useStage,\n useTrack,\n useAudioLevel,\n useHandQueue,\n useMediaEffects,\n useModerationNotice,\n useMeetShortcuts,\n useReactions,\n MEET_SHORTCUTS,\n type UseHostControlsResult,\n} from \"./hooks\";\nimport {\n createCameraPreview,\n videoEffectsSupported,\n type CameraPreview,\n} from \"../core/livekit-driver\";\nimport type { VideoEffect } from \"../core/room-driver\";\nimport type { MediaEffects, RoomChatMessage } from \"../core/store\";\nimport { listenOnlyNotice } from \"../core/attendance\";\nimport {\n groupTranscript,\n guestRecordAccessExplanation,\n guestRecordAccessLabel,\n GUEST_RECORD_ACCESS_CHOICES,\n hasEnded,\n meetingWhen,\n playableRecordingFileId,\n recordingNotice,\n absenceSentence,\n REFUSED_ABSENCE,\n summarizeMeetingRecordRestrictions,\n wasRefused,\n wrapUpStatus,\n} from \"../core/record\";\nimport { isNoteTaker } from \"../core/note-taker\";\nimport {\n useDeviceSnapshot,\n useIsHost,\n useMeetHost,\n useMeetSnapshot,\n useRequiredMeetHost,\n useRole,\n type MeetHost,\n} from \"./provider\";\n\n/* ------------------------------------------------------------------ inert */\n\n/**\n * 🚨 A COMPONENT IN THIS FILE NEVER THROWS BECAUSE THE PROVIDER IS INERT.\n *\n * `<MeetProvider>` is deliberately inert until a Supabase client, an\n * organization and an identity are all real — which is every server render,\n * every signed-out visitor, and every moment before the active organization\n * hydrates. Through 0.2.0 the entry components called `useRequiredMeetHost()`\n * unconditionally, so the README's own three-line integration returned a 500 on\n * every route for those visitors, and the first real consumer had to guard OUR\n * components in ITS code (register MRI-D1, matrx-frontend 2026-09-08). That is\n * exactly the massage C22 forbids, and the defect was ours.\n *\n * The rule from 0.2.1 on: an entry component either renders its product or an\n * HONEST sentence — `<InertNotice>` below — and the ambient, always-mounted\n * ones (`<IncomingCallHost>`, `<CallButton>`, `<RecordingIndicator>`) render\n * NOTHING, because there is nothing truthful to say about a call surface on a\n * page with no runtime. Internal children (`<DevicePicker>`, `<HostMenu>`,\n * `<WaitingRoom>`) keep `useRequiredMeetHost()`: they are only ever rendered\n * BELOW one of these guards, so an absent host there is a package bug and must\n * be loud.\n */\nfunction InertNotice({ what }: { what: string }): ReactNode {\n return (\n <div className=\"mx-meet__empty\" role=\"status\">\n <p className=\"mx-meet__empty-title\">{what} is not ready yet</p>\n <p className=\"mx-meet__empty-body\">\n Calls and meetings need a signed-in identity and an active organization. This will\n appear as soon as they resolve.\n </p>\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ parts */\n\nexport function Avatar({\n name,\n url,\n size = 40,\n}: {\n name: string;\n url?: string | null;\n size?: number;\n}): ReactNode {\n const tint = avatarPaletteIndex(name);\n if (url != null && url.length > 0) {\n return (\n <img\n className=\"mx-meet__avatar\"\n src={url}\n alt=\"\"\n width={size}\n height={size}\n style={{ width: size, height: size }}\n />\n );\n }\n return (\n <span\n className=\"mx-meet__avatar mx-meet__avatar--initials\"\n style={{\n width: size,\n height: size,\n fontSize: Math.round(size * 0.38),\n background: `var(--mx-meet-avatar-${tint})`,\n }}\n aria-hidden=\"true\"\n >\n {getInitials(name)}\n </span>\n );\n}\n\nexport function ControlButton({\n label,\n active = false,\n danger = false,\n onClick,\n children,\n}: {\n label: string;\n active?: boolean;\n danger?: boolean;\n onClick: () => void;\n children: ReactNode;\n}): ReactNode {\n return (\n <button\n type=\"button\"\n className={[\n \"mx-meet__control\",\n active ? \"mx-meet__control--active\" : \"\",\n danger ? \"mx-meet__control--danger\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n // The accessible name is the STATE, not the icon: \"Unmute\" when muted.\n aria-label={label}\n title={label}\n onClick={onClick}\n >\n {children}\n </button>\n );\n}\n\n/**\n * The recording indicator. Rendered for EVERY participant, guests included —\n * there is no prop that hides it (R5). Consent is a property of the package.\n */\nexport function RecordingIndicator(): ReactNode {\n const { state, label } = useRecording();\n if (label === null) return null;\n return (\n <span\n className={`mx-meet__recording mx-meet__recording--${state}`}\n role=\"status\"\n aria-live=\"polite\"\n >\n <RecordIcon width={10} height={10} />\n {label}\n </span>\n );\n}\n\nexport function ConnectionDot({ quality }: { quality: string }): ReactNode {\n if (quality === \"excellent\" || quality === \"good\" || quality === \"unknown\") return null;\n // Only shown when it MEANS something. A permanent green dot teaches people\n // to ignore the indicator that matters.\n return (\n <span className={`mx-meet__quality mx-meet__quality--${quality}`} title={`Connection ${quality}`}>\n <WifiLowIcon width={14} height={14} />\n </span>\n );\n}\n\n/* ------------------------------------------------------------------- tile */\n\n/** Host, Co-host or Guest — and nothing at all for an ordinary participant. */\nfunction RoleBadge({ role }: { role: ParticipantRole }): ReactNode {\n if (role === \"host\") return <span className=\"mx-meet__badge\">Host</span>;\n if (role === \"cohost\") return <span className=\"mx-meet__badge\">Co-host</span>;\n if (role === \"guest\") return <span className=\"mx-meet__badge\">Guest</span>;\n return null;\n}\n\nexport function ParticipantTile({\n participant,\n featured = false,\n}: {\n participant: MeetParticipant;\n featured?: boolean;\n}): ReactNode {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const queue = useHandQueue();\n const [menu, setMenu] = useState(false);\n const videoRef = useTrack(\n participant.identity,\n participant.screenSharing ? \"screen\" : \"camera\",\n );\n const showVideo = participant.cameraEnabled || participant.screenSharing;\n const pinnedHere = snapshot?.pinned === participant.identity;\n const spotlit = snapshot?.spotlight === participant.identity;\n const handPosition = participant.handRaised\n ? queue.findIndex((entry) => entry.identity === participant.identity) + 1\n : 0;\n\n return (\n <div\n className={[\n \"mx-meet__tile\",\n featured ? \"mx-meet__tile--featured\" : \"\",\n participant.speaking ? \"mx-meet__tile--speaking\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n data-identity={participant.identity}\n >\n {showVideo ? (\n <video\n ref={videoRef}\n className=\"mx-meet__video\"\n autoPlay\n playsInline\n muted={participant.isLocal}\n />\n ) : (\n <div className=\"mx-meet__tile-placeholder\">\n <Avatar name={participant.displayName} url={participant.avatarUrl} size={featured ? 96 : 56} />\n </div>\n )}\n\n {participant.handRaised ? (\n <span className=\"mx-meet__tile-hand\" title={`Hand raised · ${ordinal(handPosition)} in line`}>\n <HandIcon width={14} height={14} />\n {handPosition > 0 ? handPosition : null}\n </span>\n ) : null}\n\n <div className=\"mx-meet__tile-bar\">\n <span className=\"mx-meet__tile-name\">\n {spotlit ? (\n <span title=\"Spotlighted for everyone\" className=\"mx-meet__tile-flag\">\n <SpotlightIcon width={12} height={12} />\n </span>\n ) : null}\n {participant.displayName}\n {participant.isLocal ? \" (you)\" : \"\"}\n {/* An agent is LABELLED. An invisible listener is the thing nobody\n should ever ship. */}\n {participant.isAgent ? <span className=\"mx-meet__badge\">AI</span> : null}\n {/* ONE role badge in this package (MRI-A11). */}\n <RoleBadge role={participant.role} />\n </span>\n {!participant.micEnabled ? <MicOffIcon width={14} height={14} /> : null}\n <QualityBars quality={participant.quality} />\n </div>\n\n <div className={menu ? \"mx-meet__tile-actions mx-meet__tile-actions--open\" : \"mx-meet__tile-actions\"}>\n <ControlButton\n label={pinnedHere ? \"Unpin\" : `Pin ${participant.displayName} for me`}\n active={pinnedHere}\n onClick={() => host?.engine.pin(pinnedHere ? null : participant.identity)}\n >\n <PinIcon width={16} height={16} />\n </ControlButton>\n <span className=\"mx-meet__anchor\">\n <ControlButton\n label={`More for ${participant.displayName}`}\n active={menu}\n onClick={() => setMenu(!menu)}\n >\n <MoreIcon width={16} height={16} />\n </ControlButton>\n {menu ? (\n <PersonMenu participant={participant} onClose={() => setMenu(false)} placement=\"down\" />\n ) : null}\n </span>\n </div>\n </div>\n );\n}\n\nfunction ordinal(position: number): string {\n if (position <= 0) return \"\";\n const suffix =\n position % 100 >= 11 && position % 100 <= 13\n ? \"th\"\n : ({ 1: \"st\", 2: \"nd\", 3: \"rd\" } as Record<number, string>)[position % 10] ?? \"th\";\n return `${position}${suffix}`;\n}\n\n/**\n * CONNECTION QUALITY, always legible (Meet wave 2). Four bars, like every phone:\n * a stable good connection is quiet (the bars are there, faint), and a poor or\n * lost one is loud. `unknown` draws nothing — a guess is not a reading.\n */\nexport function QualityBars({ quality }: { quality: string }): ReactNode {\n if (quality === \"unknown\") return null;\n const bars = quality === \"excellent\" ? 3 : quality === \"good\" ? 2 : quality === \"poor\" ? 1 : 0;\n const label =\n quality === \"lost\" ? \"Connection lost\" : quality === \"poor\" ? \"Poor connection\" : `Connection ${quality}`;\n return (\n <span className={`mx-meet__signal mx-meet__signal--${quality}`} title={label} aria-label={label} role=\"img\">\n <SignalIcon bars={bars as 0 | 1 | 2 | 3} width={14} height={14} />\n </span>\n );\n}\n\n/* ------------------------------------------------------------------ stage */\n\nexport function Stage({ pageSize }: { pageSize?: number }): ReactNode {\n const stage = useStage(pageSize);\n const columns = gridColumns(stage.tiles.length);\n\n if (stage.feature === null && stage.tiles.length === 0) {\n return (\n <div className=\"mx-meet__stage mx-meet__stage--empty\">\n <p className=\"mx-meet__empty-title\">Waiting for others to join</p>\n <p className=\"mx-meet__empty-body\">\n Share the meeting link and people can join from anywhere — no account needed.\n </p>\n </div>\n );\n }\n\n return (\n <div className={`mx-meet__stage${stage.feature !== null ? \" mx-meet__stage--speaker\" : \"\"}`}>\n {stage.feature !== null ? (\n <ParticipantTile participant={stage.feature} featured />\n ) : null}\n <div\n className=\"mx-meet__grid\"\n style={{ \"--mx-meet-columns\": columns } as React.CSSProperties}\n >\n {stage.tiles.map((participant) => (\n <ParticipantTile key={participant.identity} participant={participant} />\n ))}\n </div>\n {stage.overflow > 0 ? (\n <p className=\"mx-meet__overflow\">\n +{stage.overflow} more {stage.overflow === 1 ? \"person\" : \"people\"} in this meeting\n </p>\n ) : null}\n </div>\n );\n}\n\n/* ------------------------------------------------------------- control bar */\n\ntype Panel = \"none\" | \"chat\" | \"people\" | \"ai\" | \"settings\";\n\n/** Meet's own reaction set, in its order. */\nexport const MEET_REACTIONS: readonly string[] = [\"💖\", \"👍\", \"🎉\", \"👏\", \"😂\", \"😮\", \"😢\", \"🤔\", \"👎\"];\n\n/**\n * THE CONTROL BAR — one row, the same in the package's room and in any host\n * layout that composes it (the Board). Everything a person does in a meeting is\n * reachable from here or from the panels it opens, and every keyboard shortcut\n * is bound here, so a layout that renders this bar has all of it.\n */\nexport function ControlBar({ onLeave }: { onLeave?: () => void }): ReactNode {\n const room = useRoom();\n const recording = useRecording();\n const [panel, setPanel] = useState<Panel>(\"none\");\n const [chatTo, setChatTo] = useState<ParticipantIdentity | null>(null);\n const [popover, setPopover] = useState<\"none\" | \"reactions\" | \"more\">(\"none\");\n const [shortcuts, setShortcuts] = useState(false);\n const snapshot = useMeetSnapshot();\n const lobby = useLobby();\n const controls = useHostControls();\n const queue = useHandQueue();\n const micUnavailable = useLocalMedia().microphone.unavailable;\n const unread = useUnreadChat(panel === \"chat\");\n\n const toggle = (next: Panel) => setPanel(panel === next ? \"none\" : next);\n\n useMeetShortcuts({\n mic: () => void room.toggleMicrophone(),\n camera: () => void room.toggleCamera(),\n hand: () => void room.toggleHand(),\n chat: () => toggle(\"chat\"),\n people: () => toggle(\"people\"),\n help: () => setShortcuts(true),\n });\n\n const hasSpotlight = snapshot?.spotlight !== null && snapshot?.spotlight !== undefined;\n\n return (\n <>\n <MeetingOverlays />\n {shortcuts ? <ShortcutsSheet onClose={() => setShortcuts(false)} /> : null}\n {panel === \"chat\" ? (\n <ChatPanel onClose={() => setPanel(\"none\")} to={chatTo} onTo={setChatTo} />\n ) : null}\n {panel === \"people\" ? (\n <PeoplePanel\n onClose={() => setPanel(\"none\")}\n onMessage={(identity) => {\n setChatTo(identity);\n setPanel(\"chat\");\n }}\n />\n ) : null}\n {panel === \"ai\" ? <AiPanel onClose={() => setPanel(\"none\")} /> : null}\n {panel === \"settings\" ? <SettingsPanel onClose={() => setPanel(\"none\")} /> : null}\n\n {/* The People panel says it inline, beside the row it acted on. */}\n {controls.notice !== null && panel !== \"people\" ? (\n <Toast text={controls.notice.text} failed={controls.notice.failed} onDone={controls.clearNotice} />\n ) : null}\n\n <div className=\"mx-meet__controls\">\n {/* The label states the REFUSAL when there is one, so the control is\n never a button that looks like it should work and doesn't. */}\n <ControlButton\n label={\n micUnavailable !== null\n ? `Unmute — ${micUnavailable.remedy}`\n : room.local?.micEnabled === true\n ? \"Mute (⌘D)\"\n : \"Unmute (⌘D)\"\n }\n active={room.local?.micEnabled === true}\n onClick={() => void room.toggleMicrophone()}\n >\n {room.local?.micEnabled === true ? <MicIcon /> : <MicOffIcon />}\n </ControlButton>\n\n <ControlButton\n label={room.local?.cameraEnabled === true ? \"Stop video (⌘E)\" : \"Start video (⌘E)\"}\n active={room.local?.cameraEnabled === true}\n onClick={() => void room.toggleCamera()}\n >\n {room.local?.cameraEnabled === true ? <CameraIcon /> : <CameraOffIcon />}\n </ControlButton>\n\n <ControlButton\n label={room.local?.screenSharing === true ? \"Stop sharing\" : \"Share screen\"}\n active={room.local?.screenSharing === true}\n onClick={() => void room.toggleScreenShare()}\n >\n <ScreenShareIcon />\n </ControlButton>\n\n <span className=\"mx-meet__anchor\">\n <ControlButton\n label=\"Send a reaction\"\n active={popover === \"reactions\"}\n onClick={() => setPopover(popover === \"reactions\" ? \"none\" : \"reactions\")}\n >\n <SmileIcon />\n </ControlButton>\n {popover === \"reactions\" ? (\n <Popover label=\"Reactions\" onClose={() => setPopover(\"none\")}>\n <div className=\"mx-meet__emoji-bar\">\n {MEET_REACTIONS.map((emoji) => (\n <button\n key={emoji}\n type=\"button\"\n className=\"mx-meet__emoji\"\n aria-label={`React ${emoji}`}\n onClick={() => void room.react(emoji)}\n >\n {emoji}\n </button>\n ))}\n </div>\n </Popover>\n ) : null}\n </span>\n\n <ControlButton\n label={room.local?.handRaised === true ? \"Lower hand (⌘⌥H)\" : \"Raise hand (⌘⌥H)\"}\n active={room.local?.handRaised === true}\n onClick={() => void room.toggleHand()}\n >\n <HandIcon />\n </ControlButton>\n\n <ControlButton label=\"Chat (⌘⌥C)\" active={panel === \"chat\"} onClick={() => toggle(\"chat\")}>\n <ChatIcon />\n {unread > 0 ? <span className=\"mx-meet__dot\" aria-hidden=\"true\" /> : null}\n </ControlButton>\n\n <ControlButton\n label={\n lobby.waiting.length > 0\n ? `People — ${lobby.waiting.length} waiting`\n : `People — ${(snapshot?.participants ?? []).length} in the meeting`\n }\n active={panel === \"people\"}\n onClick={() => toggle(\"people\")}\n >\n <PeopleIcon />\n {lobby.waiting.length > 0 || (controls.isHost && queue.length > 0) ? (\n <span className=\"mx-meet__dot\" aria-hidden=\"true\" />\n ) : null}\n </ControlButton>\n\n {/* The AI control appears only when the meeting's AI is on — never a\n button that resolves to \"not configured\". */}\n <AiControl active={panel === \"ai\"} onToggle={() => toggle(\"ai\")} />\n\n {recording.canStart ? (\n <ControlButton label=\"Start recording\" onClick={() => void recording.start()}>\n <RecordIcon />\n </ControlButton>\n ) : null}\n {recording.canStop ? (\n <ControlButton label=\"Stop recording\" active onClick={() => void recording.stop()}>\n <RecordIcon />\n </ControlButton>\n ) : null}\n\n <span className=\"mx-meet__anchor\">\n <ControlButton\n label=\"More options\"\n active={popover === \"more\" || panel === \"settings\"}\n onClick={() => setPopover(popover === \"more\" ? \"none\" : \"more\")}\n >\n <MoreIcon />\n </ControlButton>\n {popover === \"more\" ? (\n <Popover label=\"More options\" onClose={() => setPopover(\"none\")}>\n <div className=\"mx-meet__menu\" role=\"menu\">\n <MenuItem\n onSelect={() => {\n setPopover(\"none\");\n setPanel(\"settings\");\n }}\n >\n <SettingsIcon width={16} height={16} /> Audio, video and effects\n </MenuItem>\n <MenuItem\n onSelect={() => {\n setPopover(\"none\");\n setShortcuts(true);\n }}\n >\n <KeyboardIcon width={16} height={16} /> Keyboard shortcuts\n </MenuItem>\n {controls.isHost ? (\n <>\n <div className=\"mx-meet__menu-sep\" role=\"separator\" />\n <MenuItem\n onSelect={() => {\n setPopover(\"none\");\n void controls.run({ action: \"mute_all\" });\n }}\n >\n <MicOffIcon width={16} height={16} /> Mute everyone\n </MenuItem>\n <MenuItem\n onSelect={() => {\n setPopover(\"none\");\n void controls.run({ action: \"ask_all_unmute\" });\n }}\n >\n <MicIcon width={16} height={16} /> Ask everyone to unmute\n </MenuItem>\n {queue.length > 0 ? (\n <MenuItem\n onSelect={() => {\n setPopover(\"none\");\n void controls.run({ action: \"lower_all_hands\" });\n }}\n >\n <HandIcon width={16} height={16} /> Lower all hands ({queue.length})\n </MenuItem>\n ) : null}\n {hasSpotlight ? (\n <MenuItem\n onSelect={() => {\n setPopover(\"none\");\n void controls.run({ action: \"spotlight\", identity: null });\n }}\n >\n <SpotlightIcon width={16} height={16} /> Remove spotlight\n </MenuItem>\n ) : null}\n </>\n ) : null}\n </div>\n </Popover>\n ) : null}\n </span>\n\n <ControlButton\n label=\"Leave\"\n danger\n onClick={() => {\n void room.leave();\n onLeave?.();\n }}\n >\n <PhoneOffIcon />\n </ControlButton>\n </div>\n </>\n );\n}\n\n/** Messages that arrived while the chat panel was closed. */\nfunction useUnreadChat(open: boolean): number {\n const snapshot = useMeetSnapshot();\n const chat = snapshot?.chat ?? [];\n const local = snapshot?.localIdentity ?? null;\n const [seen, setSeen] = useState(0);\n useEffect(() => {\n if (open) setSeen(chat.length);\n }, [open, chat.length]);\n // The saved history read on join is not \"unread\" — only what arrives after it.\n const loaded = snapshot?.chatLoaded === true;\n const [baseline, setBaseline] = useState<number | null>(null);\n useEffect(() => {\n if (loaded && baseline === null) setBaseline(chat.length);\n }, [loaded, baseline, chat.length]);\n if (open) return 0;\n const from = Math.max(seen, baseline ?? chat.length);\n return chat.slice(from).filter((message) => message.identity !== local).length;\n}\n\n/**\n * A small floating surface anchored to its control. Escape and an outside click\n * close it. It is FIXED-positioned from the anchor's rectangle, because the\n * controls it hangs off live inside tiles that clip (`overflow: hidden`) and\n * inside a Board that pans — an absolutely positioned menu would be cut in half.\n */\nfunction Popover({\n label,\n onClose,\n children,\n placement = \"up\",\n}: {\n label: string;\n onClose: () => void;\n children: ReactNode;\n placement?: \"up\" | \"down\";\n}): ReactNode {\n const ref = useRef<HTMLDivElement | null>(null);\n const [style, setStyle] = useState<React.CSSProperties>({ visibility: \"hidden\" });\n useLayoutEffect(() => {\n const element = ref.current;\n const anchor = element?.parentElement ?? null;\n if (element === null || anchor === null) return;\n const place = () => {\n const rect = anchor.getBoundingClientRect();\n const width = element.offsetWidth;\n const height = element.offsetHeight;\n const gutter = 8;\n const left = Math.min(\n Math.max(gutter, rect.left + rect.width / 2 - width / 2),\n window.innerWidth - width - gutter,\n );\n const fitsBelow = rect.bottom + gutter + height <= window.innerHeight;\n const fitsAbove = rect.top - gutter - height >= 0;\n const down = placement === \"down\" ? fitsBelow || !fitsAbove : !fitsAbove && fitsBelow;\n setStyle(\n down\n ? { position: \"fixed\", left, top: rect.bottom + gutter }\n : { position: \"fixed\", left, bottom: window.innerHeight - rect.top + gutter },\n );\n };\n place();\n window.addEventListener(\"resize\", place);\n return () => window.removeEventListener(\"resize\", place);\n }, [placement]);\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n const onPointer = (event: PointerEvent) => {\n const anchor = ref.current?.parentElement ?? null;\n if (anchor !== null && !anchor.contains(event.target as Node)) onClose();\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"pointerdown\", onPointer);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"pointerdown\", onPointer);\n };\n }, [onClose]);\n return (\n <div ref={ref} className=\"mx-meet__popover\" style={style} role=\"dialog\" aria-label={label}>\n {children}\n </div>\n );\n}\n\nfunction MenuItem({\n onSelect,\n danger = false,\n children,\n}: {\n onSelect: () => void;\n danger?: boolean;\n children: ReactNode;\n}): ReactNode {\n return (\n <button\n type=\"button\"\n role=\"menuitem\"\n className={danger ? \"mx-meet__menu-item mx-meet__menu-item--danger\" : \"mx-meet__menu-item\"}\n onClick={onSelect}\n >\n {children}\n </button>\n );\n}\n\n/** A transient sentence above the control bar. Stays 4 s, or until dismissed. */\nfunction Toast({ text, failed, onDone }: { text: string; failed: boolean; onDone: () => void }): ReactNode {\n useEffect(() => {\n const timer = setTimeout(onDone, failed ? 7000 : 4000);\n return () => clearTimeout(timer);\n }, [text, failed, onDone]);\n return (\n <div className={failed ? \"mx-meet__toast mx-meet__toast--failed\" : \"mx-meet__toast\"} role=\"status\">\n <span>{text}</span>\n <button type=\"button\" className=\"mx-meet__toast-close\" aria-label=\"Dismiss\" onClick={onDone}>\n <CloseIcon width={14} height={14} />\n </button>\n </div>\n );\n}\n\n/**\n * WHAT FLOATS OVER THE MEETING, in every layout (Meet wave 2): the reactions\n * everyone sends, and what a host just did to THIS person — \"the host is asking\n * you to unmute\" with the Unmute button right there, which is the whole point.\n */\nexport function MeetingOverlays(): ReactNode {\n const reactions = useReactions();\n const { notice, dismiss } = useModerationNotice();\n const room = useRoom();\n return (\n <>\n <ReactionOverlay reactions={reactions} />\n {notice !== null && notice.kind !== \"removed\" ? (\n // A host's request (\"the host is asking you to unmute\"), not an error:\n // an assertive status, so it is announced at once without being filed\n // as a failure (design-system error-box census).\n <div className=\"mx-meet__notice-bar\" role=\"status\" aria-live=\"assertive\">\n <span>{notice.text}</span>\n {notice.kind === \"ask-unmute\" && room.local?.micEnabled !== true ? (\n <button\n type=\"button\"\n className=\"mx-meet__primary mx-meet__primary--small\"\n onClick={() => {\n dismiss();\n void room.toggleMicrophone();\n }}\n >\n Unmute\n </button>\n ) : null}\n <button type=\"button\" className=\"mx-meet__toast-close\" aria-label=\"Dismiss\" onClick={dismiss}>\n <CloseIcon width={14} height={14} />\n </button>\n </div>\n ) : null}\n </>\n );\n}\n\n/** Every shortcut, on one sheet. Opened by Shift+? or from More options. */\nexport function ShortcutsSheet({ onClose }: { onClose: () => void }): ReactNode {\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [onClose]);\n return (\n <div className=\"mx-meet__sheet-backdrop\" onClick={onClose}>\n <div\n className=\"mx-meet__sheet\"\n role=\"dialog\"\n aria-label=\"Keyboard shortcuts\"\n onClick={(event) => event.stopPropagation()}\n >\n <header className=\"mx-meet__panel-head\">\n <h2 className=\"mx-meet__panel-title\">Keyboard shortcuts</h2>\n <ControlButton label=\"Close\" onClick={onClose}>\n <CloseIcon width={16} height={16} />\n </ControlButton>\n </header>\n <dl className=\"mx-meet__shortcuts\">\n {MEET_SHORTCUTS.map((shortcut) => (\n <div key={shortcut.id} className=\"mx-meet__shortcut\">\n <dt>{shortcut.label}</dt>\n <dd>\n <kbd className=\"mx-meet__kbd\">{shortcut.keys}</kbd>\n </dd>\n </div>\n ))}\n </dl>\n </div>\n </div>\n );\n}\n\n/**\n * The assistant control. It appears for every meeting whose AI is on, because\n * as of 0.3.0 the capability is the SERVER's: there is no host config that\n * could leave it unfilled, and a meeting with no Holder bound gets the server's\n * sentence in the panel rather than a control that never appears. A meeting\n * with `ai_enabled = false` gets NO control at all — absent, not disabled.\n */\nfunction AiControl({ active, onToggle }: { active: boolean; onToggle: () => void }): ReactNode {\n const snapshot = useMeetSnapshot();\n const meeting = snapshot?.meeting ?? null;\n if (meeting === null || !meeting.aiEnabled) return null;\n return (\n <ControlButton label=\"Meeting assistant\" active={active} onClick={onToggle}>\n <SparklesIcon />\n </ControlButton>\n );\n}\n\n/* ----------------------------------------------------------------- panels */\n\nfunction PanelShell({\n title,\n onClose,\n children,\n}: {\n title: string;\n onClose: () => void;\n children: ReactNode;\n}): ReactNode {\n return (\n <aside className=\"mx-meet__panel\" aria-label={title}>\n <header className=\"mx-meet__panel-head\">\n <h2 className=\"mx-meet__panel-title\">{title}</h2>\n <ControlButton label=\"Close panel\" onClick={onClose}>\n <CloseIcon width={16} height={16} />\n </ControlButton>\n </header>\n <div className=\"mx-meet__panel-body\">{children}</div>\n </aside>\n );\n}\n\n/**\n * IN-MEETING CHAT (Meet wave 2). A message to everyone is SAVED with the\n * meeting — a late joiner scrolls up and reads it, and it is part of the record.\n * A private message goes to one person only and is never saved; the composer\n * says which of the two you are about to send.\n */\nexport function ChatPanel({\n onClose,\n to = null,\n onTo,\n}: {\n onClose: () => void;\n to?: ParticipantIdentity | null;\n onTo?: (identity: ParticipantIdentity | null) => void;\n}): ReactNode {\n const snapshot = useMeetSnapshot();\n const room = useRoom();\n const [draft, setDraft] = useState(\"\");\n const [recipient, setRecipient] = useState<ParticipantIdentity | null>(to);\n const listRef = useRef<HTMLUListElement | null>(null);\n const messages = snapshot?.chat ?? [];\n const local = snapshot?.localIdentity ?? null;\n const people = (snapshot?.participants ?? []).filter(\n (participant) => !participant.isLocal && !participant.isAgent,\n );\n const recipientName =\n recipient === null ? null : people.find((p) => p.identity === recipient)?.displayName ?? null;\n\n useEffect(() => setRecipient(to), [to]);\n useEffect(() => {\n const list = listRef.current;\n if (list !== null) list.scrollTop = list.scrollHeight;\n }, [messages.length]);\n\n const choose = (next: ParticipantIdentity | null) => {\n setRecipient(next);\n onTo?.(next);\n };\n\n return (\n <PanelShell title=\"Chat\" onClose={onClose}>\n <ul className=\"mx-meet__chat\" ref={listRef}>\n {snapshot?.chatHistoryError != null ? (\n <li className=\"mx-meet__panel-note\">{snapshot.chatHistoryError}</li>\n ) : null}\n {snapshot?.chatLoaded !== true && messages.length === 0 ? (\n <li className=\"mx-meet__panel-note\">Reading earlier messages…</li>\n ) : messages.length === 0 && snapshot?.chatHistoryError == null ? (\n <li className=\"mx-meet__panel-note\">\n No messages yet. Messages to everyone stay with the meeting, so people who join later\n see them.\n </li>\n ) : null}\n {messages.map((message) => (\n <ChatLine key={message.id} message={message} local={local} people={people} />\n ))}\n </ul>\n <form\n className=\"mx-meet__composer mx-meet__composer--chat\"\n onSubmit={(event) => {\n event.preventDefault();\n const text = draft;\n if (text.trim().length === 0) return;\n setDraft(\"\");\n if (recipient === null) void room.sendChat(text).catch(() => undefined);\n else void room.sendPrivateChat(recipient, text);\n }}\n >\n {people.length > 0 ? (\n <select\n className=\"mx-meet__select mx-meet__select--compact\"\n aria-label=\"Send to\"\n value={recipient ?? \"\"}\n onChange={(event) =>\n choose(event.target.value === \"\" ? null : (event.target.value as ParticipantIdentity))\n }\n >\n <option value=\"\">Everyone</option>\n {people.map((participant) => (\n <option key={participant.identity} value={participant.identity}>\n {participant.displayName} (private)\n </option>\n ))}\n </select>\n ) : null}\n <div className=\"mx-meet__composer-row\">\n <input\n className=\"mx-meet__input\"\n value={draft}\n onChange={(event) => setDraft(event.target.value)}\n placeholder={recipientName === null ? \"Message everyone\" : `Message ${recipientName} privately`}\n aria-label={recipientName === null ? \"Message everyone\" : `Message ${recipientName} privately`}\n maxLength={4000}\n />\n <button type=\"submit\" className=\"mx-meet__send\" disabled={draft.trim().length === 0}>\n Send\n </button>\n </div>\n {recipientName !== null ? (\n <p className=\"mx-meet__panel-note\">Only {recipientName} sees this. Private messages are not saved.</p>\n ) : null}\n </form>\n </PanelShell>\n );\n}\n\nfunction ChatLine({\n message,\n local,\n people,\n}: {\n message: RoomChatMessage;\n local: ParticipantIdentity | null;\n people: readonly MeetParticipant[];\n}): ReactNode {\n const mine = message.identity === local;\n const privateTo = message.to ?? null;\n const counterpart =\n privateTo === null\n ? null\n : mine\n ? people.find((p) => p.identity === privateTo)?.displayName ?? \"them\"\n : \"you\";\n return (\n <li\n className={[\n \"mx-meet__chat-line\",\n privateTo !== null ? \"mx-meet__chat-line--private\" : \"\",\n message.failed !== undefined ? \"mx-meet__chat-line--failed\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n <span className=\"mx-meet__chat-meta\">\n <strong>{mine ? \"You\" : message.displayName}</strong>\n {counterpart !== null ? <span className=\"mx-meet__chat-private\">to {counterpart} · private</span> : null}\n <time dateTime={message.at}>{clockOf(message.at)}</time>\n </span>\n <span className=\"mx-meet__chat-text\">{message.text}</span>\n {message.failed !== undefined ? (\n <span className=\"mx-meet__chat-failed\">{message.failed}</span>\n ) : privateTo === null && message.saved === false ? (\n <span className=\"mx-meet__chat-pending\">\n {message.id.startsWith(\"pending-\") ? \"Sending…\" : \"Not saved — people who join later will not see this\"}\n </span>\n ) : null}\n </li>\n );\n}\n\nexport function PeoplePanel({\n onClose,\n onMessage,\n}: {\n onClose: () => void;\n onMessage?: (identity: ParticipantIdentity) => void;\n}): ReactNode {\n const snapshot = useMeetSnapshot();\n const controls = useHostControls();\n const queue = useHandQueue();\n const [query, setQuery] = useState(\"\");\n const [menuFor, setMenuFor] = useState<ParticipantIdentity | null>(null);\n // THE LOCAL ROW IS BADGED FROM THE EFFECTIVE ROLE (MRI-A11).\n const myRole = useRole();\n const local = snapshot?.localIdentity ?? null;\n const everyone = snapshot?.participants ?? [];\n const needle = query.trim().toLowerCase();\n const shown =\n needle.length === 0\n ? everyone\n : everyone.filter((participant) => participant.displayName.toLowerCase().includes(needle));\n\n return (\n <PanelShell title={`People (${everyone.length})`} onClose={onClose}>\n <LobbyPanel />\n\n {queue.length > 0 ? (\n <section className=\"mx-meet__section\" aria-label=\"Raised hands\">\n <header className=\"mx-meet__section-head\">\n <h3 className=\"mx-meet__section-title\">Raised hands · {queue.length}</h3>\n {controls.isHost ? (\n <button\n type=\"button\"\n className=\"mx-meet__link\"\n onClick={() => void controls.run({ action: \"lower_all_hands\" })}\n >\n Lower all\n </button>\n ) : null}\n </header>\n <ol className=\"mx-meet__queue\">\n {queue.map((participant) => (\n <li key={participant.identity} className=\"mx-meet__person\">\n <Avatar name={participant.displayName} url={participant.avatarUrl} size={28} />\n <span className=\"mx-meet__person-name\">\n {participant.displayName}\n {participant.identity === local ? <span className=\"mx-meet__you\"> (you)</span> : null}\n </span>\n {controls.isHost || participant.identity === local ? (\n <button\n type=\"button\"\n className=\"mx-meet__link\"\n onClick={() =>\n void controls.run({ action: \"lower_hand\", identity: participant.identity })\n }\n >\n Lower\n </button>\n ) : null}\n </li>\n ))}\n </ol>\n </section>\n ) : null}\n\n {controls.isHost && everyone.length > 1 ? (\n <div className=\"mx-meet__bulk\">\n <button type=\"button\" className=\"mx-meet__chip\" onClick={() => void controls.run({ action: \"mute_all\" })}>\n <MicOffIcon width={14} height={14} /> Mute all\n </button>\n <button\n type=\"button\"\n className=\"mx-meet__chip\"\n onClick={() => void controls.run({ action: \"ask_all_unmute\" })}\n >\n <MicIcon width={14} height={14} /> Ask all to unmute\n </button>\n </div>\n ) : null}\n\n {everyone.length > 4 ? (\n <label className=\"mx-meet__search\">\n <SearchIcon width={16} height={16} />\n <input\n className=\"mx-meet__input mx-meet__input--bare\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder=\"Search people\"\n aria-label=\"Search people\"\n />\n </label>\n ) : null}\n\n {controls.notice !== null ? (\n <p className={controls.notice.failed ? \"mx-meet__error\" : \"mx-meet__notice\"} role=\"status\">\n {controls.notice.text}\n </p>\n ) : null}\n\n <ul className=\"mx-meet__people\">\n {shown.map((participant) => (\n <li key={participant.identity} className=\"mx-meet__person\">\n <Avatar name={participant.displayName} url={participant.avatarUrl} size={32} />\n <span className=\"mx-meet__person-name\">\n {participant.displayName}\n {participant.identity === local ? <span className=\"mx-meet__you\"> (you)</span> : null}\n <RoleBadge role={participant.identity === local ? myRole : participant.role} />\n {isNoteTaker(participant) ? (\n <span className=\"mx-meet__badge\">Meeting assistant</span>\n ) : null}\n {snapshot?.spotlight === participant.identity ? (\n <span className=\"mx-meet__badge\">Spotlight</span>\n ) : null}\n </span>\n {participant.handRaised ? <HandIcon width={14} height={14} /> : null}\n {!participant.micEnabled && !isNoteTaker(participant) ? (\n <MicOffIcon width={14} height={14} />\n ) : null}\n <QualityBars quality={participant.quality} />\n <span className=\"mx-meet__anchor\">\n <ControlButton\n label={`More for ${participant.displayName}`}\n active={menuFor === participant.identity}\n onClick={() => setMenuFor(menuFor === participant.identity ? null : participant.identity)}\n >\n <MoreIcon width={16} height={16} />\n </ControlButton>\n {menuFor === participant.identity ? (\n <PersonMenu\n participant={participant}\n placement=\"down\"\n onClose={() => setMenuFor(null)}\n {...(onMessage !== undefined ? { onMessage } : {})}\n />\n ) : null}\n </span>\n </li>\n ))}\n {shown.length === 0 ? <li className=\"mx-meet__panel-note\">Nobody matches “{query}”.</li> : null}\n </ul>\n\n {/* MRF-1: a host decides what the guests in this list will be able to read\n afterwards, WHILE the meeting is running — which is when they know. */}\n {snapshot?.meeting !== null && snapshot?.meeting !== undefined ? (\n <GuestRecordAccessControl meeting={snapshot.meeting} />\n ) : null}\n </PanelShell>\n );\n}\n\n/**\n * EVERYTHING YOU CAN DO ABOUT ONE PERSON (Meet wave 2), in one menu — on their\n * tile and on their People row. An item appears only when it would be honoured:\n * the rank ladder decides moderation (a co-host never sees \"Remove\" on the host),\n * only the host sees \"Make host\", and nobody sees a control that the server\n * would refuse. Removing someone and handing the meeting over NAME THEIR\n * CONSEQUENCE first, inline — never a browser dialog.\n */\nexport function PersonMenu({\n participant,\n onClose,\n onMessage,\n placement = \"down\",\n}: {\n participant: MeetParticipant;\n onClose: () => void;\n onMessage?: (identity: ParticipantIdentity) => void;\n placement?: \"up\" | \"down\";\n}): ReactNode {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const controls = useHostControls();\n const [mode, setMode] = useState<\"menu\" | \"rename\" | \"report\" | \"remove\" | \"transfer\">(\"menu\");\n const [text, setText] = useState(\"\");\n const self = participant.identity === snapshot?.localIdentity;\n const moderate = controls.canModerate(participant);\n const pinned = snapshot?.pinned === participant.identity;\n const spotlit = snapshot?.spotlight === participant.identity;\n const hasAccount = participant.userId !== null;\n const act = (request: Parameters<UseHostControlsResult[\"run\"]>[0]) => {\n void controls.run(request).then((result) => {\n if (result !== null) onClose();\n });\n };\n\n if (mode === \"rename\" || mode === \"report\") {\n const renaming = mode === \"rename\";\n return (\n <Popover label={renaming ? \"Rename\" : \"Report\"} onClose={onClose} placement={placement}>\n <form\n className=\"mx-meet__menu-form\"\n onSubmit={(event) => {\n event.preventDefault();\n if (text.trim().length === 0) return;\n act(\n renaming\n ? { action: \"rename\", identity: participant.identity, name: text.trim() }\n : { action: \"report\", identity: participant.identity, reason: text.trim() },\n );\n }}\n >\n <label className=\"mx-meet__field\">\n <span className=\"mx-meet__field-label\">\n {renaming ? \"Name shown in this meeting\" : `What did ${participant.displayName} do?`}\n </span>\n {renaming ? (\n <input\n className=\"mx-meet__input\"\n autoFocus\n maxLength={80}\n value={text}\n onChange={(event) => setText(event.target.value)}\n />\n ) : (\n <textarea\n className=\"mx-meet__input\"\n autoFocus\n rows={3}\n maxLength={1000}\n value={text}\n onChange={(event) => setText(event.target.value)}\n />\n )}\n </label>\n {controls.notice?.failed === true ? <p className=\"mx-meet__error\">{controls.notice.text}</p> : null}\n <div className=\"mx-meet__menu-actions\">\n <button type=\"button\" className=\"mx-meet__link\" onClick={() => setMode(\"menu\")}>\n Back\n </button>\n <button type=\"submit\" className=\"mx-meet__send\" disabled={text.trim().length === 0 || controls.busy}>\n {renaming ? \"Rename\" : \"Report\"}\n </button>\n </div>\n </form>\n </Popover>\n );\n }\n\n if (mode === \"remove\" || mode === \"transfer\") {\n const removing = mode === \"remove\";\n return (\n <Popover label={removing ? \"Remove\" : \"Make host\"} onClose={onClose} placement={placement}>\n <div className=\"mx-meet__menu-form\">\n <p className=\"mx-meet__confirm-text\">\n {removing\n ? `Remove ${participant.displayName}? They leave immediately and cannot rejoin this meeting.`\n : `Make ${participant.displayName} the host? They get every host control and own this meeting. You stay on as a co-host.`}\n </p>\n <div className=\"mx-meet__menu-actions\">\n <button type=\"button\" className=\"mx-meet__link\" onClick={() => setMode(\"menu\")}>\n Cancel\n </button>\n <button\n type=\"button\"\n className={removing ? \"mx-meet__send mx-meet__send--danger\" : \"mx-meet__send\"}\n disabled={controls.busy}\n onClick={() =>\n act({ action: removing ? \"remove\" : \"transfer_host\", identity: participant.identity })\n }\n >\n {removing ? \"Remove\" : \"Make host\"}\n </button>\n </div>\n </div>\n </Popover>\n );\n }\n\n return (\n <Popover label={`Options for ${participant.displayName}`} onClose={onClose} placement={placement}>\n <div className=\"mx-meet__menu\" role=\"menu\">\n <MenuItem\n onSelect={() => {\n host?.engine.pin(pinned ? null : participant.identity);\n onClose();\n }}\n >\n <PinIcon width={16} height={16} /> {pinned ? \"Unpin\" : \"Pin for me\"}\n </MenuItem>\n {!self && !participant.isAgent && onMessage !== undefined ? (\n <MenuItem\n onSelect={() => {\n onMessage(participant.identity);\n onClose();\n }}\n >\n <ChatIcon width={16} height={16} /> Message privately\n </MenuItem>\n ) : null}\n {controls.isHost ? (\n <MenuItem onSelect={() => act({ action: \"spotlight\", identity: spotlit ? null : participant.identity })}>\n <SpotlightIcon width={16} height={16} /> {spotlit ? \"Remove spotlight\" : \"Spotlight for everyone\"}\n </MenuItem>\n ) : null}\n {moderate ? (\n <>\n <div className=\"mx-meet__menu-sep\" role=\"separator\" />\n {participant.micEnabled ? (\n <MenuItem onSelect={() => act({ action: \"mute\", identity: participant.identity })}>\n <MicOffIcon width={16} height={16} /> Mute\n </MenuItem>\n ) : !participant.isAgent ? (\n <MenuItem onSelect={() => act({ action: \"ask_unmute\", identity: participant.identity })}>\n <MicIcon width={16} height={16} /> Ask to unmute\n </MenuItem>\n ) : null}\n {participant.cameraEnabled ? (\n <MenuItem onSelect={() => act({ action: \"stop_video\", identity: participant.identity })}>\n <CameraOffIcon width={16} height={16} /> Stop video\n </MenuItem>\n ) : null}\n {participant.screenSharing ? (\n <MenuItem onSelect={() => act({ action: \"stop_screen\", identity: participant.identity })}>\n <ScreenShareIcon width={16} height={16} /> Stop screen share\n </MenuItem>\n ) : null}\n {participant.handRaised ? (\n <MenuItem onSelect={() => act({ action: \"lower_hand\", identity: participant.identity })}>\n <HandIcon width={16} height={16} /> Lower hand\n </MenuItem>\n ) : null}\n {hasAccount && !participant.isAgent && participant.role !== \"cohost\" ? (\n <MenuItem onSelect={() => act({ action: \"make_cohost\", identity: participant.identity })}>\n <PeopleIcon width={16} height={16} /> Make co-host\n </MenuItem>\n ) : null}\n {!participant.isAgent ? (\n <MenuItem\n onSelect={() => {\n setText(participant.displayName);\n setMode(\"rename\");\n }}\n >\n <PencilIcon width={16} height={16} /> Rename\n </MenuItem>\n ) : null}\n </>\n ) : null}\n {controls.isOwner && participant.role === \"cohost\" ? (\n <MenuItem onSelect={() => act({ action: \"revoke_cohost\", identity: participant.identity })}>\n <PeopleIcon width={16} height={16} /> Remove co-host\n </MenuItem>\n ) : null}\n {controls.isOwner && !self && hasAccount && !participant.isAgent ? (\n <MenuItem onSelect={() => setMode(\"transfer\")}>\n <SpotlightIcon width={16} height={16} /> Make host\n </MenuItem>\n ) : null}\n {self ? (\n <MenuItem\n onSelect={() => {\n setText(participant.displayName);\n setMode(\"rename\");\n }}\n >\n <PencilIcon width={16} height={16} /> Rename yourself\n </MenuItem>\n ) : null}\n {!self && !participant.isAgent ? (\n <MenuItem\n onSelect={() => {\n setText(\"\");\n setMode(\"report\");\n }}\n >\n <FlagIcon width={16} height={16} /> Report\n </MenuItem>\n ) : null}\n {moderate && !participant.isAgent ? (\n <MenuItem danger onSelect={() => setMode(\"remove\")}>\n <CloseIcon width={16} height={16} /> Remove from meeting\n </MenuItem>\n ) : null}\n </div>\n </Popover>\n );\n}\n\n/* --------------------------------------------------------------- settings */\n\n/**\n * AUDIO, VIDEO AND EFFECTS (Meet wave 2) — the devices in use, a live\n * microphone level, a speaker test, noise suppression and the camera\n * background. Every change applies to the live meeting at once and is\n * remembered in this browser.\n */\nexport function SettingsPanel({ onClose }: { onClose: () => void }): ReactNode {\n const host = useRequiredMeetHost();\n return (\n <PanelShell title=\"Audio, video and effects\" onClose={onClose}>\n <DeviceSettings\n onPick={(kind, deviceId) => {\n host.devices.select(kind, deviceId);\n void host.engine.switchDevice(kind, deviceId);\n }}\n />\n <EffectsSettings />\n </PanelShell>\n );\n}\n\n/** Microphone (with a live level), speaker (with a test), camera. */\nfunction DeviceSettings({\n onPick,\n}: {\n onPick: (kind: \"audioinput\" | \"videoinput\" | \"audiooutput\", deviceId: string) => void;\n}): ReactNode {\n const host = useRequiredMeetHost();\n const devices = useDeviceSnapshot();\n const microphone = devices?.selected.audioinput ?? host.devices.resolve(\"audioinput\");\n const speaker = devices?.selected.audiooutput ?? host.devices.resolve(\"audiooutput\");\n const stream = useMicrophoneStream(microphone);\n const level = useAudioLevel(stream);\n const [testing, setTesting] = useState(false);\n\n useEffect(() => {\n void host.devices.refresh();\n }, [host]);\n\n return (\n <section className=\"mx-meet__section\" aria-label=\"Devices\">\n <DevicePicker kind=\"audioinput\" label=\"Microphone\" onPick={onPick} />\n <div className=\"mx-meet__meter\" role=\"meter\" aria-label=\"Microphone level\" aria-valuemin={0} aria-valuemax={100} aria-valuenow={Math.round(level * 100)}>\n <span style={{ width: `${Math.min(100, Math.round(level * 160))}%` }} />\n </div>\n <DevicePicker kind=\"audiooutput\" label=\"Speaker\" onPick={onPick} />\n <button\n type=\"button\"\n className=\"mx-meet__chip\"\n disabled={testing}\n onClick={() => {\n setTesting(true);\n void playTestSound(speaker).finally(() => setTesting(false));\n }}\n >\n <SpeakerIcon width={14} height={14} /> {testing ? \"Playing…\" : \"Test speaker\"}\n </button>\n <DevicePicker kind=\"videoinput\" label=\"Camera\" onPick={onPick} />\n </section>\n );\n}\n\n/** Noise suppression and the camera background. */\nfunction EffectsSettings({ preview }: { preview?: CameraPreview | null }): ReactNode {\n const effects = useMediaEffects();\n const [error, setError] = useState<string | null>(null);\n const fileRef = useRef<HTMLInputElement | null>(null);\n // Pre-join there is no room driver yet, so the browser itself is asked.\n const supported = effects.backgroundsSupported || preview != null || videoEffectsSupported();\n\n const apply = (next: Partial<MediaEffects>) => {\n setError(null);\n void effects.set(next);\n if (preview != null) {\n const merged = { ...effects.effects, ...next };\n void preview.setEffect(toVideoEffect(merged)).catch(() =>\n setError(\"This browser could not run the background effect.\"),\n );\n }\n };\n\n return (\n <section className=\"mx-meet__section\" aria-label=\"Effects\">\n <label className=\"mx-meet__toggle\">\n <input\n type=\"checkbox\"\n checked={effects.effects.noiseSuppression}\n onChange={(event) => apply({ noiseSuppression: event.target.checked })}\n />\n Noise suppression\n <span className=\"mx-meet__hint\">Filters keyboards, fans and background chatter.</span>\n </label>\n {supported ? (\n <div className=\"mx-meet__field\">\n <span className=\"mx-meet__field-label\">Background</span>\n <div className=\"mx-meet__pills\" role=\"radiogroup\" aria-label=\"Background\">\n {([\"none\", \"blur\", \"image\"] as const).map((kind) => (\n <button\n key={kind}\n type=\"button\"\n role=\"radio\"\n aria-checked={effects.effects.background === kind}\n className={\n effects.effects.background === kind ? \"mx-meet__pill mx-meet__pill--on\" : \"mx-meet__pill\"\n }\n onClick={() => {\n if (kind === \"image\") {\n fileRef.current?.click();\n return;\n }\n apply({ background: kind });\n }}\n >\n {kind === \"none\" ? \"None\" : kind === \"blur\" ? \"Blur\" : \"Picture…\"}\n </button>\n ))}\n </div>\n <input\n ref={fileRef}\n type=\"file\"\n accept=\"image/*\"\n hidden\n onChange={(event) => {\n const file = event.target.files?.[0];\n event.target.value = \"\";\n if (file === undefined) return;\n void shrinkImage(file)\n .then((url) => apply({ background: \"image\", backgroundImage: url }))\n .catch(() => setError(\"That picture could not be read. Try a JPEG or PNG.\"));\n }}\n />\n {error !== null ? <p className=\"mx-meet__error\">{error}</p> : null}\n </div>\n ) : null}\n </section>\n );\n}\n\nfunction toVideoEffect(effects: MediaEffects): VideoEffect {\n if (effects.background === \"blur\") return { kind: \"blur\" };\n if (effects.background === \"image\" && effects.backgroundImage !== null) {\n return { kind: \"image\", imageUrl: effects.backgroundImage };\n }\n return { kind: \"none\" };\n}\n\n/**\n * A picked background, scaled to 1280 px wide as a JPEG data URL — small enough\n * to remember in this browser (a `blob:` URL dies with the tab), large enough\n * for a 720p camera.\n */\nasync function shrinkImage(file: File): Promise<string> {\n const url = URL.createObjectURL(file);\n try {\n const image = new Image();\n image.src = url;\n await image.decode();\n const scale = Math.min(1, 1280 / image.naturalWidth);\n const canvas = document.createElement(\"canvas\");\n canvas.width = Math.round(image.naturalWidth * scale);\n canvas.height = Math.round(image.naturalHeight * scale);\n const context = canvas.getContext(\"2d\");\n if (context === null) throw new Error(\"no 2d context\");\n context.drawImage(image, 0, 0, canvas.width, canvas.height);\n return canvas.toDataURL(\"image/jpeg\", 0.85);\n } finally {\n URL.revokeObjectURL(url);\n }\n}\n\n/** A short two-tone chime through the chosen speaker. */\nasync function playTestSound(sinkId: string | null): Promise<void> {\n const Context = (globalThis as { AudioContext?: typeof AudioContext }).AudioContext;\n if (Context === undefined) return;\n const context = new Context();\n const destination = context.createMediaStreamDestination();\n const gain = context.createGain();\n gain.gain.value = 0.2;\n gain.connect(destination);\n for (const [frequency, start] of [\n [660, 0],\n [880, 0.25],\n ] as const) {\n const oscillator = context.createOscillator();\n oscillator.frequency.value = frequency;\n oscillator.connect(gain);\n oscillator.start(context.currentTime + start);\n oscillator.stop(context.currentTime + start + 0.22);\n }\n const audio = new Audio();\n audio.srcObject = destination.stream;\n const sinkable = audio as HTMLAudioElement & { setSinkId?: (id: string) => Promise<void> };\n if (sinkId !== null && sinkId !== \"default\" && sinkable.setSinkId !== undefined) {\n await sinkable.setSinkId(sinkId).catch(() => undefined);\n }\n await audio.play().catch(() => undefined);\n await new Promise((resolve) => setTimeout(resolve, 700));\n audio.pause();\n await context.close();\n}\n\n/** A microphone stream for the level meter only — closed with the component. */\nfunction useMicrophoneStream(deviceId: string | null | \"off\"): MediaStream | null {\n const [stream, setStream] = useState<MediaStream | null>(null);\n useEffect(() => {\n if (deviceId === \"off\") return undefined;\n let live = true;\n let opened: MediaStream | null = null;\n const media = (globalThis as { navigator?: Navigator }).navigator?.mediaDevices;\n if (media === undefined) return undefined;\n void media\n .getUserMedia({ audio: deviceId === null ? true : { deviceId: { exact: deviceId } } })\n .then((next) => {\n if (!live) {\n next.getTracks().forEach((track) => track.stop());\n return;\n }\n opened = next;\n setStream(next);\n })\n .catch(() => setStream(null));\n return () => {\n live = false;\n opened?.getTracks().forEach((track) => track.stop());\n setStream(null);\n };\n }, [deviceId]);\n return stream;\n}\n\n/** The waiting room. Rendered for hosts only — a participant sees nothing. */\nexport function LobbyPanel(): ReactNode {\n const lobby = useLobby();\n if (!lobby.canAdmit || lobby.waiting.length === 0) return null;\n return (\n <section className=\"mx-meet__lobby\" aria-label=\"Waiting room\">\n <header className=\"mx-meet__lobby-head\">\n <h3 className=\"mx-meet__lobby-title\">\n {lobby.waiting.length === 1\n ? \"1 person is waiting\"\n : `${lobby.waiting.length} people are waiting`}\n </h3>\n <button type=\"button\" className=\"mx-meet__link\" onClick={() => void lobby.admitAll()}>\n Admit all\n </button>\n </header>\n <ul className=\"mx-meet__lobby-list\">\n {lobby.waiting.map((entry) => (\n <li key={entry.identity} className=\"mx-meet__lobby-row\">\n <Avatar name={entry.displayName} url={entry.avatarUrl} size={32} />\n <span className=\"mx-meet__person-name\">\n {entry.displayName}\n {entry.userId === null ? <span className=\"mx-meet__badge\">Guest</span> : null}\n </span>\n <ControlButton label={`Admit ${entry.displayName}`} onClick={() => void lobby.admit(entry)}>\n <CheckIcon width={16} height={16} />\n </ControlButton>\n <ControlButton\n label={`Deny ${entry.displayName}`}\n danger\n onClick={() => void lobby.deny(entry)}\n >\n <CloseIcon width={16} height={16} />\n </ControlButton>\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\n/**\n * THE NOTE-TAKER'S STATE, on screen, with the server's own words.\n *\n * 🚨 NEVER A SPINNER. Every one of the five states (D9/MRI-A2) has a sentence,\n * and a refused dispatch shows the SERVER's `reason` and `remedy` verbatim —\n * \"no worker is registered under matrx-note-taker\", and what to do about it.\n * Through 0.2.1 a failed dispatch threw and the panel showed a remedy with no\n * state behind it; a person could not tell \"it refused\" from \"it is coming\".\n */\nfunction NoteTakerRow(): ReactNode {\n const ai = useMeetAi();\n const status = ai.noteTaker;\n const duplicateError =\n status.refusal !== null &&\n ai.error !== null &&\n status.refusal.reason === ai.error.message &&\n status.refusal.remedy === ai.error.remedy;\n return (\n <section className=\"mx-meet__note-taker\" aria-label=\"Note-taker\">\n <p className={`mx-meet__note-taker-state mx-meet__note-taker-state--${status.state}`}>\n <span className=\"mx-meet__note-taker-dot\" aria-hidden=\"true\" />\n {ai.noteTakerLabel}\n </p>\n {status.detail !== null ? (\n <p className=\"mx-meet__panel-note\">{status.detail}</p>\n ) : null}\n\n {/* THE REFUSAL, VERBATIM. Not summarized, not replaced by a house\n sentence, and not hidden behind a retry that would refuse again. */}\n {status.refusal !== null ? (\n <ErrorBox as=\"div\" className=\"mx-meet__refusal\" error={status.refusal} operation=\"Join this meeting\" origin=\"meet/components\">\n <p className=\"mx-meet__refusal-reason\">{status.refusal.reason}</p>\n {status.refusal.remedy.length > 0 ? (\n <p className=\"mx-meet__refusal-remedy\">{status.refusal.remedy}</p>\n ) : null}\n </ErrorBox>\n ) : null}\n\n {ai.error !== null && !duplicateError ? (\n <ErrorBox as=\"div\" className=\"mx-meet__refusal\" error={ai.error} operation=\"Run the meeting assistant\" origin=\"meet/components\">\n <p className=\"mx-meet__refusal-reason\">{ai.error.message}</p>\n <p className=\"mx-meet__refusal-remedy\">{ai.error.remedy}</p>\n </ErrorBox>\n ) : null}\n\n {/* A control an actor cannot use is ABSENT (no dead ends). A guest and a\n non-host see the STATE and no buttons at all. */}\n {ai.canControlNoteTaker ? (\n status.state === \"transcribing\" ||\n status.state === \"joining\" ||\n status.state === \"handoff_pending\" ? (\n <button\n type=\"button\"\n className=\"mx-meet__link\"\n onClick={() => void ai.stopNoteTaker()}\n >\n Dismiss the note-taker\n </button>\n ) : (\n <button\n type=\"button\"\n className=\"mx-meet__primary\"\n onClick={() => void ai.startNoteTaker()}\n >\n Start note-taker\n </button>\n )\n ) : null}\n </section>\n );\n}\n\nfunction NoteList({\n title,\n notes,\n empty,\n}: {\n title: string;\n notes: readonly { id: string; text: string; assigneeDisplayName?: string | null }[];\n empty: string;\n}): ReactNode {\n return (\n <section className=\"mx-meet__note-group\" aria-label={title}>\n <h3 className=\"mx-meet__note-group-title\">{title}</h3>\n {notes.length === 0 ? (\n <p className=\"mx-meet__panel-note\">{empty}</p>\n ) : (\n <ul className=\"mx-meet__notes\">\n {notes.map((note) => (\n <li key={note.id} className=\"mx-meet__note\">\n {note.text}\n {/* D18: a guest never gets an `assignee_user_id`, so the name is\n read from the row's metadata — an action item whose owner has\n no name is an action item nobody owns. */}\n {note.assigneeDisplayName !== undefined &&\n note.assigneeDisplayName !== null ? (\n <span className=\"mx-meet__assignee\">{note.assigneeDisplayName}</span>\n ) : null}\n </li>\n ))}\n </ul>\n )}\n </section>\n );\n}\n\n/**\n * THE MEETING ASSISTANT (R4). The note-taker's state, what the meeting has\n * decided so far, the wrap-up, and a question box whose answer arrives token by\n * token.\n *\n * Nothing on this panel is computed here: notes, decisions and action items are\n * durable rows delivered by Postgres Changes, and the answer is streamed from\n * `/intelligence/ask`, which builds it from those same rows. The captions this\n * client can see are never sent anywhere (D16).\n */\nexport function AiPanel({ onClose }: { onClose: () => void }): ReactNode {\n const ai = useMeetAi();\n const [question, setQuestion] = useState(\"\");\n\n return (\n <PanelShell title=\"Meeting assistant\" onClose={onClose}>\n <NoteTakerRow />\n\n {ai.summary !== null ? (\n <section className=\"mx-meet__note-group\" aria-label=\"Summary\">\n <h3 className=\"mx-meet__note-group-title\">Summary</h3>\n <p className=\"mx-meet__summary\">{ai.summary.text}</p>\n </section>\n ) : null}\n\n {/*\n THE WRAP-UP, ANNOUNCED IN THE ROOM (MRI-A12). It says the pass FINISHED,\n which is the one thing the notes above cannot say for themselves — a\n panel with no summary is otherwise indistinguishable from a summary that\n is still being written. It is absent, never a placeholder, when nothing\n was announced: on the ordinary ending path the room is deleted before the\n pass runs, and the summary is read on the post-meeting record instead.\n */}\n {ai.wrapUp !== null ? (\n <p className=\"mx-meet__wrap-up-notice\" role=\"status\">\n The wrap-up is written — {ai.wrapUp.noteIds.length}{\" \"}\n {ai.wrapUp.noteIds.length === 1 ? \"entry\" : \"entries\"} from{\" \"}\n {ai.wrapUp.segmentCount}{\" \"}\n {ai.wrapUp.segmentCount === 1 ? \"transcript line\" : \"transcript lines\"}.\n </p>\n ) : null}\n\n <NoteList\n title=\"Notes\"\n notes={ai.notes}\n empty=\"Notes appear here as the meeting goes on.\"\n />\n <NoteList\n title=\"Decisions\"\n notes={ai.decisions}\n empty=\"Nothing has been decided yet.\"\n />\n <NoteList\n title=\"Action items\"\n notes={ai.actionItems}\n empty=\"No action items yet.\"\n />\n\n {ai.transcript.length > 0 ? (\n <section className=\"mx-meet__note-group\" aria-label=\"Transcript\">\n <h3 className=\"mx-meet__note-group-title\">Transcript</h3>\n <ul className=\"mx-meet__transcript\">\n {ai.transcript.map((line) => (\n <li\n key={line.id}\n className={\n line.final && line.source === \"record\"\n ? \"mx-meet__line\"\n : \"mx-meet__line mx-meet__line--interim\"\n }\n >\n <strong>{line.speaker}</strong>\n <span>{line.text}</span>\n </li>\n ))}\n </ul>\n </section>\n ) : null}\n\n <form\n className=\"mx-meet__composer\"\n onSubmit={(event) => {\n event.preventDefault();\n const asked = question;\n setQuestion(\"\");\n void ai.ask(asked);\n }}\n >\n <input\n className=\"mx-meet__input\"\n value={question}\n onChange={(event) => setQuestion(event.target.value)}\n placeholder=\"Ask about this meeting\"\n aria-label=\"Ask about this meeting\"\n />\n <button type=\"submit\" className=\"mx-meet__send\" disabled={ai.asking}>\n {ai.asking ? \"Asking…\" : \"Ask\"}\n </button>\n </form>\n\n {/* THE SERVER'S PHASE, not a spinner of our invention. */}\n {ai.asking && ai.phase !== null ? (\n <p className=\"mx-meet__panel-note\" role=\"status\">\n {ai.phase}\n </p>\n ) : null}\n {ai.answer !== null ? <p className=\"mx-meet__answer\">{ai.answer}</p> : null}\n {/* WHAT THE ANSWER WAS BUILT FROM. The server measures it; a truncated\n transcript is stated rather than quietly answered around. */}\n {ai.answer !== null && ai.coverage !== null ? (\n <p className=\"mx-meet__coverage\">\n Answered from {ai.coverage.segmentsUsed} of {ai.coverage.segmentsTotal} transcript\n lines\n {ai.coverage.truncated ? \" (the oldest were left out)\" : \"\"}.\n </p>\n ) : null}\n {/* THE REMEDY, not a shrug — and rendered by THIS hook instance, because\n `useMeetAi()` holds its own ask state per component. */}\n {ai.error !== null ? (\n <ErrorBox as=\"div\" className=\"mx-meet__refusal\" error={ai.error} operation=\"Run the meeting assistant\" origin=\"meet/components\">\n <p className=\"mx-meet__refusal-reason\">{ai.error.message}</p>\n <p className=\"mx-meet__refusal-remedy\">{ai.error.remedy}</p>\n </ErrorBox>\n ) : null}\n </PanelShell>\n );\n}\n\n/**\n * LIVE CAPTIONS. The last few lines, over the stage, for anyone who reads\n * faster than they hear.\n *\n * They are HINTS (D16) — the durable segment replaces the line it captioned as\n * soon as the row lands — so an unsettled line renders differently from a\n * settled one and nothing downstream ever reads this list.\n */\nexport function Captions({ lines = 3 }: { lines?: number }): ReactNode {\n const ai = useMeetAi();\n const visible = ai.transcript.slice(-lines);\n if (visible.length === 0) return null;\n return (\n <div className=\"mx-meet__captions\" aria-live=\"polite\" aria-label=\"Live captions\">\n {visible.map((line) => (\n <p\n key={line.id}\n className={\n line.final ? \"mx-meet__caption\" : \"mx-meet__caption mx-meet__caption--interim\"\n }\n >\n <strong>{line.speaker}</strong> {line.text}\n </p>\n ))}\n </div>\n );\n}\n\n/**\n * CONSENT IS NOT A PROP (README rule 8, D10).\n *\n * Whenever an agent participant is in the room, EVERY participant sees this —\n * host, member and guest alike. There is no prop that hides it and no host code\n * involved: through 0.2.1 the first real consumer had to write this banner\n * itself by reading `isAgent` off the roster, which is exactly the massage C22\n * forbids.\n */\nexport function ConsentNotice(): ReactNode {\n const notice = useConsentNotice();\n if (notice === null) return null;\n return (\n <p className=\"mx-meet__consent\" role=\"status\">\n {notice}\n </p>\n );\n}\n\n/**\n * LISTEN-ONLY ATTENDANCE, said out loud. Shown whenever the local participant\n * is in the room publishing no microphone — whether they chose that or the\n * browser refused. When it was refused, the browser's own reason and the remedy\n * are shown too, because \"others can't hear you\" without \"and here is why\"\n * leaves someone clicking a mute button that cannot work.\n */\nexport function AttendanceNotice(): ReactNode {\n const media = useLocalMedia();\n const notice = listenOnlyNotice(media);\n if (notice === null) return null;\n const refused = media.microphone.unavailable;\n return (\n <p className=\"mx-meet__banner mx-meet__banner--attendance\" role=\"status\">\n {notice}\n {refused === null ? null : <span className=\"mx-meet__remedy\">{refused.remedy}</span>}\n </p>\n );\n}\n\n/* --------------------------------------------------------------- pre-join */\n\nexport function PreJoin(props: {\n roomName: RoomName;\n meetingId?: string;\n slug?: string;\n onJoined?: () => void;\n}): ReactNode {\n // THE GUARD, not a throw. See <InertNotice>.\n const host = useMeetHost();\n if (host === null) return <InertNotice what=\"This meeting\" />;\n return <PreJoinBody {...props} host={host} />;\n}\n\nfunction PreJoinBody({\n roomName,\n meetingId,\n slug,\n onJoined,\n host,\n}: {\n roomName: RoomName;\n meetingId?: string;\n slug?: string;\n onJoined?: () => void;\n host: MeetHost;\n}): ReactNode {\n const room = useRoom();\n const devices = useDeviceSnapshot();\n const recording = useRecording();\n const effects = useMediaEffects();\n const { notice } = useModerationNotice();\n const [mode, setMode] = useState<CallMode>(\"video\");\n // Attendance is not contingent on a device (see core/attendance.ts), so this\n // is an ordinary choice, not a gate. Unchecking it joins listen-only; leaving\n // it checked and having the browser refuse ALSO joins, listen-only, with the\n // refusal's own remedy shown in the room.\n const [microphone, setMicrophone] = useState(true);\n const [joining, setJoining] = useState(false);\n const camera = devices?.selected.videoinput ?? host.devices.resolve(\"videoinput\");\n const mic = devices?.selected.audioinput ?? host.devices.resolve(\"audioinput\");\n const preview = useCameraPreview(mode === \"video\" ? camera : undefined, effects.effects);\n const micStream = useMicrophoneStream(microphone ? mic : \"off\");\n const level = useAudioLevel(micStream);\n const [speakerTesting, setSpeakerTesting] = useState(false);\n\n useEffect(() => {\n void host.devices.refresh();\n }, [host]);\n\n return (\n <div className=\"mx-meet__prejoin\">\n <div className=\"mx-meet__preview\">\n {mode === \"video\" && preview.preview !== null ? (\n <video\n className=\"mx-meet__video mx-meet__video--mirror\"\n autoPlay\n playsInline\n muted\n ref={(element) => {\n if (element !== null) preview.preview?.attach(element);\n }}\n />\n ) : (\n <div className=\"mx-meet__tile-placeholder\">\n <Avatar name={host.identity.displayName} url={host.identity.avatarUrl} size={96} />\n </div>\n )}\n {mode === \"video\" && preview.error !== null ? (\n <p className=\"mx-meet__preview-note\">{preview.error}</p>\n ) : null}\n {microphone && micStream !== null ? (\n <div className=\"mx-meet__meter mx-meet__meter--preview\" role=\"meter\" aria-label=\"Microphone level\" aria-valuemin={0} aria-valuemax={100} aria-valuenow={Math.round(level * 100)}>\n <span style={{ width: `${Math.min(100, Math.round(level * 160))}%` }} />\n </div>\n ) : null}\n </div>\n\n <div className=\"mx-meet__prejoin-panel\">\n <h1 className=\"mx-meet__prejoin-title\">Ready to join?</h1>\n\n {notice?.kind === \"removed\" ? <p className=\"mx-meet__warning\">{notice.text}</p> : null}\n\n {devices?.labelsHidden === true ? (\n <p className=\"mx-meet__panel-note\">\n Your browser is hiding device names until you allow camera and microphone access.\n <button\n type=\"button\"\n className=\"mx-meet__link\"\n onClick={() => {\n void host.devices.requestPermission({ audio: true, video: true });\n }}\n >\n Allow access\n </button>\n </p>\n ) : null}\n\n {/* A FALLBACK ANNOUNCES ITSELF — an unplugged headset never silently\n becomes the laptop mic. */}\n {devices?.fallbackNotice != null ? (\n <p className=\"mx-meet__warning\">{devices.fallbackNotice}</p>\n ) : null}\n\n <DevicePicker kind=\"audioinput\" label=\"Microphone\" />\n <div className=\"mx-meet__field-row\">\n <DevicePicker kind=\"audiooutput\" label=\"Speaker\" />\n <button\n type=\"button\"\n className=\"mx-meet__chip\"\n disabled={speakerTesting}\n onClick={() => {\n setSpeakerTesting(true);\n void playTestSound(devices?.selected.audiooutput ?? host.devices.resolve(\"audiooutput\")).finally(\n () => setSpeakerTesting(false),\n );\n }}\n >\n <SpeakerIcon width={14} height={14} /> {speakerTesting ? \"Playing…\" : \"Test\"}\n </button>\n </div>\n <DevicePicker kind=\"videoinput\" label=\"Camera\" />\n <EffectsSettings preview={preview.preview} />\n\n {recording.consentNotice !== null ? (\n <p className=\"mx-meet__consent\">{recording.consentNotice}</p>\n ) : null}\n\n <div className=\"mx-meet__prejoin-actions\">\n <label className=\"mx-meet__toggle\">\n <input\n type=\"checkbox\"\n checked={mode === \"video\"}\n onChange={(event) => setMode(event.target.checked ? \"video\" : \"audio\")}\n />\n Join with video\n </label>\n <label className=\"mx-meet__toggle\">\n <input\n type=\"checkbox\"\n checked={microphone}\n onChange={(event) => setMicrophone(event.target.checked)}\n />\n Join with microphone\n </label>\n <button\n type=\"button\"\n className=\"mx-meet__primary\"\n onClick={() => {\n setJoining(true);\n // The preview hands the camera back before the room takes it.\n preview.release();\n void room\n .join({\n roomName,\n mode,\n microphone,\n ...(meetingId !== undefined ? { meetingId } : {}),\n ...(slug !== undefined ? { slug } : {}),\n })\n .then(() => onJoined?.())\n .finally(() => setJoining(false));\n }}\n >\n {joining ? \"Joining…\" : \"Join now\"}\n </button>\n </div>\n\n {room.failure !== null ? (\n <p className=\"mx-meet__error\">\n {room.failure.message}\n <span className=\"mx-meet__remedy\">{room.failure.remedy}</span>\n </p>\n ) : null}\n </div>\n </div>\n );\n}\n\n/**\n * The pre-join camera, WITH the chosen background — the same SDK track and\n * processor the room uses. `undefined` device = camera not wanted (no preview,\n * no light). A refused camera is a sentence, never a black box.\n */\nfunction useCameraPreview(\n deviceId: string | null | undefined,\n effects: MediaEffects,\n): { preview: CameraPreview | null; error: string | null; release: () => void } {\n const [preview, setPreview] = useState<CameraPreview | null>(null);\n const [error, setError] = useState<string | null>(null);\n const current = useRef<CameraPreview | null>(null);\n const initialEffect = useRef(toVideoEffect(effects));\n initialEffect.current = toVideoEffect(effects);\n useEffect(() => {\n if (deviceId === undefined) return undefined;\n let live = true;\n setError(null);\n void createCameraPreview(deviceId, initialEffect.current)\n .then((created) => {\n if (!live) {\n created.stop();\n return;\n }\n current.current = created;\n setPreview(created);\n })\n .catch((thrown: unknown) => {\n if (!live) return;\n const failure = thrown as { message?: string; remedy?: string };\n // The person reads the sentence and its remedy — never the operation tag\n // (\"meet.cameraPreview: …\") a diagnostic carries.\n const message = (failure.message ?? \"\").replace(/^meet\\.[A-Za-z.()]+:\\s*/, \"\");\n const sentence = message.length > 0 ? message.charAt(0).toUpperCase() + message.slice(1) : \"\";\n setError([sentence, failure.remedy].filter(Boolean).join(\". \") || \"The camera did not start.\");\n });\n return () => {\n live = false;\n current.current?.stop();\n current.current = null;\n setPreview(null);\n };\n }, [deviceId]);\n return {\n preview,\n error,\n release: () => {\n current.current?.stop();\n current.current = null;\n setPreview(null);\n },\n };\n}\n\nfunction DevicePicker({\n kind,\n label,\n onPick,\n}: {\n kind: \"audioinput\" | \"videoinput\" | \"audiooutput\";\n label: string;\n /** In the room: also switch the live device. Pre-join: the choice is applied on join. */\n onPick?: (kind: \"audioinput\" | \"videoinput\" | \"audiooutput\", deviceId: string) => void;\n}): ReactNode {\n const host = useRequiredMeetHost();\n const devices = useDeviceSnapshot();\n const list = devices?.devices[kind] ?? [];\n // A browser that cannot route audio output (Safari, Firefox without the flag)\n // lists no outputs — the picker is then absent, never a select that lies.\n if (list.length === 0) return null;\n return (\n <label className=\"mx-meet__field\">\n <span className=\"mx-meet__field-label\">{label}</span>\n <select\n className=\"mx-meet__select\"\n value={devices?.selected[kind] ?? host.devices.resolve(kind) ?? \"\"}\n onChange={(event) => {\n if (onPick !== undefined) onPick(kind, event.target.value);\n else host.devices.select(kind, event.target.value);\n }}\n >\n {list.map((device) => (\n <option key={device.deviceId} value={device.deviceId}>\n {device.label.length > 0 ? device.label : `${label} (name hidden)`}\n </option>\n ))}\n </select>\n </label>\n );\n}\n\n/* ----------------------------------------------------------- meeting room */\n\nexport function MeetingRoom(props: {\n roomName: RoomName;\n meetingId?: string;\n slug?: string;\n /**\n * The meeting the host already resolved, when it has one (MRI-D2).\n *\n * 🚨 THIS IS WHAT MAKES AN ENDED MEETING WORK FOR A GUEST. Only\n * `meet_meeting_by_slug` is granted to `anon`; the `meet_meetings` TABLE is\n * not, so the durable-feed backfill — a table read — is refused for a\n * link-follower and `snapshot.meeting` stays null for them forever. A\n * consumer that resolved the slug through the RPC (every consumer does, to\n * get the room name) passes the row here, and the record renders for exactly\n * the reader who has nothing else.\n */\n meeting?: MeetingRecord;\n onLeave?: () => void;\n /**\n * A HOST-PROVIDED control for the in-meeting header — the host app's own\n * affordances that belong to the meeting (matrx-frontend puts its\n * Intelligence icon for the meeting's AI jobs here). Rendered in the header\n * row of the live room only; the pre-join, lobby and record screens carry\n * none. The package never inspects it, and styles nothing inside it.\n */\n headerControls?: ReactNode;\n}): ReactNode {\n // THE GUARD, not a throw. See <InertNotice>.\n const host = useMeetHost();\n if (host === null) {\n return (\n <div className=\"mx-meet\">\n <InertNotice what=\"This meeting\" />\n </div>\n );\n }\n return <MeetingRoomBody {...props} host={host} />;\n}\n\nfunction MeetingRoomBody({\n roomName,\n meetingId,\n slug,\n meeting: given,\n onLeave,\n headerControls,\n host,\n}: {\n roomName: RoomName;\n meetingId?: string;\n slug?: string;\n meeting?: MeetingRecord;\n onLeave?: () => void;\n headerControls?: ReactNode;\n host: MeetHost;\n}): ReactNode {\n const snapshot = useMeetSnapshot();\n const isHost = useIsHost();\n const elapsed = useElapsed(snapshot?.meeting?.startedAt ?? null);\n const phase = snapshot?.phase ?? \"idle\";\n\n useEffect(() => {\n host.meetings.watch(roomName);\n }, [host, roomName]);\n\n // 🚨 THE RESOLVED ROW SEEDS THE SNAPSHOT, AND THAT IS THE WHOLE GUEST LANE\n // (MRI-A12). `snapshot.meeting` was only ever written by the Postgres Changes\n // subscription and its backfill — both of which read the `meet_meetings`\n // TABLE, which `anon` cannot select. So for a session-less guest it stayed\n // null FOREVER, and everything keyed on it silently did not exist: no\n // Meeting-assistant control (so no notes, decisions or action items on\n // screen), no live captions (`room.ts` drops a caption with no meeting to\n // reconcile it against), and no room event that has to be matched to this\n // meeting. A guest sat in a working room with none of the meeting's\n // intelligence, and nothing said so.\n //\n // The consumer already resolved the row through `meet_meeting_by_slug` — the\n // one door that IS granted to `anon` — and hands it here. Seeding it is what\n // makes \"the resolved row travels with the room\" true rather than aspirational.\n // Written ONCE, only when the store has nothing: the durable feed's copy is\n // the record and must never be overwritten by the prop it started from.\n useEffect(() => {\n if (given === undefined) return;\n if (host.store.snapshot().meeting !== null) return;\n host.store.patch({ meeting: given, locked: given.locked });\n }, [host, given]);\n\n // THE DURABLE FEED. Transcript rows, notes and the meeting row itself (which\n // carries the note-taker's state) arrive by Postgres Changes, and the\n // subscription's own backfill reads all three on open and after every\n // reconnect — realtime has no replay, so reconnecting IS re-reading.\n const watchedId = meetingId ?? snapshot?.meeting?.id ?? null;\n useEffect(() => {\n if (watchedId === null) return;\n host.meetings.watchMeeting(asMeetingId(watchedId));\n }, [host, watchedId]);\n\n // 🚨 AN ENDED MEETING IS A RECORD, NOT A PRE-JOIN SCREEN (MRI-D2).\n //\n // The live snapshot wins when it has one (a meeting that ends WHILE somebody\n // is on this screen flips to the record on the same realtime event that\n // stamped `ended_at`); the resolved row the consumer handed us is the\n // fallback, and it is the only one a guest ever has. Before this, the durable\n // link resolved to `<PreJoin>` for a room that no longer existed — offering\n // to join a finished meeting, with the whole wrap-up unreachable.\n const record = snapshot?.meeting ?? given ?? null;\n if (hasEnded(record) && phase !== \"connected\" && phase !== \"reconnecting\") {\n return <MeetingRecordView meeting={record as MeetingRecord} />;\n }\n\n if (phase === \"idle\" || phase === \"failed\" || phase === \"left\") {\n return (\n <div className=\"mx-meet\">\n <PreJoin\n roomName={roomName}\n {...(meetingId !== undefined ? { meetingId } : {})}\n {...(slug !== undefined ? { slug } : {})}\n />\n </div>\n );\n }\n\n if (phase === \"lobby\") {\n return (\n <div className=\"mx-meet mx-meet--lobby\">\n <WaitingRoom roomName={roomName} host={host} />\n </div>\n );\n }\n\n return (\n <div className=\"mx-meet\">\n <ConsentNotice />\n <AttendanceNotice />\n <header className=\"mx-meet__header\">\n <h1 className=\"mx-meet__title\">{snapshot?.meeting?.title ?? \"Meeting\"}</h1>\n <span className=\"mx-meet__meta\">\n {participantSummary(snapshot?.participants ?? [])}\n {elapsed > 0 ? ` · ${formatDurationMs(elapsed)}` : \"\"}\n </span>\n <RecordingIndicator />\n {snapshot?.locked === true ? (\n <span className=\"mx-meet__badge\">\n <LockIcon width={12} height={12} /> Locked\n </span>\n ) : null}\n {headerControls !== undefined && headerControls !== null ? (\n <span className=\"mx-meet__header-controls\" data-meet-header-controls=\"\">\n {headerControls}\n </span>\n ) : null}\n {isHost ? <HostMenu /> : null}\n </header>\n\n {/* A reconnect is VISIBLE. A frozen tile with no explanation is\n indistinguishable from a crashed app. */}\n {phase === \"reconnecting\" ? (\n <p className=\"mx-meet__banner\" role=\"status\">\n Reconnecting…\n </p>\n ) : null}\n\n <Stage />\n <Captions />\n <ControlBar {...(onLeave !== undefined ? { onLeave } : {})} />\n </div>\n );\n}\n\nfunction WaitingRoom({ roomName, host }: { roomName: RoomName; host: MeetHost }): ReactNode {\n const knocked = useRef(false);\n useEffect(() => {\n if (knocked.current) return;\n knocked.current = true;\n host.meetings.knock(roomName);\n }, [host, roomName]);\n\n return (\n <div className=\"mx-meet__waiting\">\n <Avatar name={host.identity.displayName} url={host.identity.avatarUrl} size={72} />\n <h1 className=\"mx-meet__prejoin-title\">Waiting for the host to let you in</h1>\n <p className=\"mx-meet__empty-body\">\n You are in the waiting room as {host.identity.displayName}. You will join automatically\n once you are admitted.\n </p>\n </div>\n );\n}\n\nexport function HostMenu(): ReactNode {\n const host = useRequiredMeetHost();\n const snapshot = useMeetSnapshot();\n const end = useEndMeeting();\n // ENDING A MEETING IS DESTRUCTIVE AND IRREVERSIBLE, so the click that does it\n // names the consequence first — inline, never `window.confirm` (no browser\n // dialogs).\n const [confirmingEnd, setConfirmingEnd] = useState(false);\n const locked = snapshot?.locked === true;\n return (\n <div className=\"mx-meet__host-menu\">\n <button\n type=\"button\"\n className=\"mx-meet__link\"\n onClick={() => {\n void host.meetings.setLock(!locked);\n }}\n >\n {locked ? \"Unlock meeting\" : \"Lock meeting\"}\n </button>\n {/* ENDING IT IS A HOST POWER AND A SERVER DECISION (MRI-A6). The button\n is real; a server that does not serve the route yet earns a SENTENCE\n rather than a dead control or a silent no-op. */}\n {end.canEnd ? (\n confirmingEnd ? (\n <span className=\"mx-meet__confirm\" role=\"group\" aria-label=\"End this meeting?\">\n <span className=\"mx-meet__confirm-text\">\n End it for everyone? Every participant is disconnected, the note-taker stops, and the\n wrap-up is written. Nobody can rejoin this meeting afterwards.\n </span>\n <button\n type=\"button\"\n className=\"mx-meet__link mx-meet__link--danger\"\n onClick={() => {\n setConfirmingEnd(false);\n void end.end();\n }}\n >\n End it\n </button>\n <button\n type=\"button\"\n className=\"mx-meet__link\"\n onClick={() => setConfirmingEnd(false)}\n >\n Keep it running\n </button>\n </span>\n ) : (\n <button\n type=\"button\"\n className=\"mx-meet__link mx-meet__link--danger\"\n onClick={() => setConfirmingEnd(true)}\n >\n {end.ending ? \"Ending…\" : \"End meeting for everyone\"}\n </button>\n )\n ) : null}\n {end.notice !== null ? (\n <span className=\"mx-meet__notice\" role=\"status\">\n {end.notice}\n </span>\n ) : null}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ calls */\n\n/** Drop this next to a person and calling works. That is the whole contract. */\nexport function CallButton({\n person,\n mode = \"video\",\n children,\n}: {\n person: CallablePerson;\n mode?: CallMode;\n children?: ReactNode;\n}): ReactNode {\n const calls = useCalls();\n // A guest identity renders NOTHING — not a disabled button (D6, no dead ends).\n if (!calls.canCall) return null;\n return (\n <button\n type=\"button\"\n className=\"mx-meet__call-button\"\n onClick={() => {\n void calls.call([person.userId], mode);\n }}\n aria-label={`Call ${person.displayName}`}\n >\n {children ?? <PhoneIcon width={18} height={18} />}\n </button>\n );\n}\n\n/**\n * Mount ONCE, high in the tree. Every incoming call rings here, on whatever\n * surface the user is on (R2).\n */\nexport function IncomingCallHost(): ReactNode {\n const calls = useCalls();\n if (calls.incoming.length === 0) return null;\n return (\n <div className=\"mx-meet__ringing-stack\">\n {calls.incoming.map((invite) => (\n <IncomingCallCard key={invite.id} invite={invite} />\n ))}\n </div>\n );\n}\n\nexport function IncomingCallCard({ invite }: { invite: CallInvite }): ReactNode {\n const calls = useCalls();\n return (\n <section className=\"mx-meet__ringing\" role=\"alertdialog\" aria-label=\"Incoming call\">\n <Avatar name={invite.callerName} url={invite.callerAvatarUrl} size={56} />\n <div className=\"mx-meet__ringing-text\">\n <strong>{invite.callerName}</strong>\n <span>{invite.mode === \"video\" ? \"Incoming video call\" : \"Incoming call\"}</span>\n </div>\n <div className=\"mx-meet__ringing-actions\">\n <ControlButton label=\"Decline\" danger onClick={() => void calls.decline(invite)}>\n <PhoneOffIcon />\n </ControlButton>\n {invite.mode === \"video\" ? (\n <ControlButton\n label=\"Accept without video\"\n onClick={() => void calls.accept({ ...invite, mode: \"audio\" })}\n >\n <CameraOffIcon />\n </ControlButton>\n ) : null}\n <ControlButton label=\"Accept\" onClick={() => void calls.accept(invite)}>\n <PhoneIcon />\n </ControlButton>\n </div>\n </section>\n );\n}\n\n/* ------------------------------------------------------------- scheduling */\n\nexport function ScheduleMeeting(props: {\n /** Where meeting links point. `meetingLink` is the ONE link shape. */\n appBaseUrl: string;\n onScheduled?: (slug: string) => void;\n}): ReactNode {\n // THE GUARD, not a throw. See <InertNotice>.\n const host = useMeetHost();\n if (host === null) return <InertNotice what=\"Scheduling a meeting\" />;\n return <ScheduleMeetingBody {...props} host={host} />;\n}\n\nfunction ScheduleMeetingBody({\n appBaseUrl,\n onScheduled,\n host,\n}: {\n appBaseUrl: string;\n onScheduled?: (slug: string) => void;\n host: MeetHost;\n}): ReactNode {\n const [title, setTitle] = useState(\"\");\n const [when, setWhen] = useState(\"\");\n const [kind, setKind] = useState<MeetingKind>(\"scheduled\");\n const [busy, setBusy] = useState(false);\n const [link, setLink] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const disabled = useMemo(() => title.trim().length === 0 || busy, [title, busy]);\n\n return (\n <form\n className=\"mx-meet__schedule\"\n onSubmit={(event) => {\n event.preventDefault();\n if (host.identity.userId === null) return;\n setBusy(true);\n setError(null);\n void host.repository\n .getOrCreateMeeting({\n organizationId: host.identity.organizationId,\n hostUserId: host.identity.userId,\n title: title.trim(),\n kind,\n scheduledFor: when.length > 0 ? new Date(when).toISOString() : null,\n })\n .then((meeting) => {\n setLink(meetingLink(appBaseUrl, meeting.slug));\n onScheduled?.(meeting.slug);\n })\n .catch((thrown: unknown) => {\n setError(\n (thrown as { remedy?: string }).remedy ??\n (thrown as Error).message ??\n \"The meeting could not be created.\",\n );\n })\n .finally(() => setBusy(false));\n }}\n >\n <label className=\"mx-meet__field\">\n <span className=\"mx-meet__field-label\">Title</span>\n <input\n className=\"mx-meet__input\"\n value={title}\n onChange={(event) => setTitle(event.target.value)}\n placeholder=\"Weekly sync\"\n />\n </label>\n\n <label className=\"mx-meet__field\">\n <span className=\"mx-meet__field-label\">When</span>\n <input\n className=\"mx-meet__input\"\n type=\"datetime-local\"\n value={when}\n onChange={(event) => setWhen(event.target.value)}\n />\n </label>\n\n <label className=\"mx-meet__field\">\n <span className=\"mx-meet__field-label\">Repeats</span>\n <select\n className=\"mx-meet__select\"\n value={kind}\n onChange={(event) => setKind(event.target.value as MeetingKind)}\n >\n <option value=\"scheduled\">Once</option>\n <option value=\"recurring\">Recurring — one link, every time</option>\n </select>\n </label>\n\n <button type=\"submit\" className=\"mx-meet__primary\" disabled={disabled}>\n {busy ? \"Creating…\" : \"Create meeting\"}\n </button>\n\n {link !== null ? (\n <p className=\"mx-meet__link-out\">\n <span>Anyone with this link can join — no account needed.</span>\n <code>{link}</code>\n </p>\n ) : null}\n {error !== null ? <p className=\"mx-meet__error\">{error}</p> : null}\n </form>\n );\n}\n\n/** Reactions floating over the stage. Expired by the store, not by hope. */\nexport function ReactionOverlay({\n reactions,\n}: {\n reactions: readonly { id: string; emoji: string }[];\n}): ReactNode {\n if (reactions.length === 0) return null;\n return (\n <div className=\"mx-meet__reactions\" aria-hidden=\"true\">\n {reactions.map((reaction) => (\n <span key={reaction.id} className=\"mx-meet__reaction\">\n {reaction.emoji}\n </span>\n ))}\n </div>\n );\n}\n\nexport type { ParticipantIdentity };\n\n/* ------------------------------------------------------ the meeting record */\n\n/**\n * THE MEETING, AFTER THE MEETING (MRI-D2).\n *\n * 🚨 THE DEFECT THIS REPLACES. A meeting produced a wrap-up summary, decisions,\n * owner-assigned action items, live-note windows, a speaker-attributed\n * transcript and a recording — and then `/meet/<slug>` rendered `<PreJoin>`,\n * offering to join a room that no longer existed. Everything the campaign built\n * after the room closed was reachable only from SQL. A durable link that\n * outlives the meeting (R3) has to resolve to the RECORD.\n *\n * The bar it is written to (PLAN §3, Fireflies/Otter recon): what was decided,\n * who owns what, what was said and by whom, and a question box over all of it.\n *\n * Nothing on this screen is computed in the browser. Every line is a durable\n * row; the answer is streamed from `/intelligence/ask`, which reads those same\n * rows server-side. A part the reader is not allowed to see says so IN WORDS —\n * an empty section is indistinguishable from a meeting where nothing happened.\n */\n\n/**\n * WHAT GUESTS MAY READ OF THIS MEETING — the host's control (MRF-1).\n *\n * 🚨 **HOST-ONLY, AND ABSENT FOR EVERYONE ELSE.** Not greyed out, not present\n * with a tooltip: a participant has no control here at all, because a control\n * that exists only to be refused is the dead-end class this package does not\n * ship (D11-style honesty, same posture as `PersonHostActions`).\n *\n * It is the third rung of the ladder Arman ruled on 2026-09-12 — the system's\n * default, the organization's setting, and this meeting's. \"Use my\n * organization's setting\" is shown WITH what that resolves to, because a label\n * that does not say what the organization chose makes the host guess about\n * other people's words.\n */\nexport function GuestRecordAccessControl({\n meeting,\n}: {\n meeting: MeetingRecord;\n}): ReactNode {\n const host = useMeetHost();\n const inRoomHost = useIsHost();\n const access = useGuestRecordAccess(meeting);\n const viewerId = host?.identity.userId ?? null;\n // The named host of the row, or a host of the room this tick. A co-host who\n // holds only an `iam` grant and is not in the room does not see the control;\n // the server would allow them, so this is the narrow side on purpose — a\n // missing control is honest, a control that lies about who may click it is not.\n const isHost = inRoomHost || (viewerId !== null && meeting.hostUserId === viewerId);\n if (host === null || !isHost) return null;\n\n const resolved =\n access.setting === \"default\" && access.effective !== null\n ? ` Right now that means: ${guestRecordAccessLabel(access.effective.level).toLowerCase()}.`\n : \"\";\n\n return (\n <section className=\"mx-meet__record-section\" aria-label=\"What guests may read\">\n <h2 className=\"mx-meet__record-section-title\">What guests may read</h2>\n <label className=\"mx-meet__field\">\n <span className=\"mx-meet__field-label\">\n People who attended by link, without an account\n </span>\n <select\n className=\"mx-meet__select\"\n value={access.setting}\n disabled={access.saving}\n onChange={(event) => {\n void access.choose(\n event.target.value as (typeof GUEST_RECORD_ACCESS_CHOICES)[number],\n );\n }}\n >\n {GUEST_RECORD_ACCESS_CHOICES.map((choice) => (\n <option key={choice} value={choice}>\n {guestRecordAccessLabel(choice)}\n </option>\n ))}\n </select>\n </label>\n <p className=\"mx-meet__panel-note\">\n {guestRecordAccessExplanation(access.setting)}\n {resolved}\n </p>\n {access.saving ? (\n <p className=\"mx-meet__panel-note\" role=\"status\">\n Saving what guests may read…\n </p>\n ) : null}\n {access.error !== null ? (\n <ErrorBox as=\"div\" className=\"mx-meet__refusal\" error={access.error} operation=\"Change who can join\" origin=\"meet/components\">\n <p className=\"mx-meet__refusal-reason\">{access.error.message}</p>\n <p className=\"mx-meet__refusal-remedy\">{access.error.remedy}</p>\n </ErrorBox>\n ) : null}\n </section>\n );\n}\n\nexport function MeetingRecordView({\n meeting,\n onRejoin,\n}: {\n meeting: MeetingRecord;\n /** Optional: a recurring link can be re-opened. Absent for a one-off. */\n onRejoin?: () => void;\n}): ReactNode {\n const host = useMeetHost();\n if (host === null) {\n return (\n <div className=\"mx-meet mx-meet--record\">\n <InertNotice what=\"This meeting record\" />\n </div>\n );\n }\n return <MeetingRecordBody meeting={meeting} {...(onRejoin !== undefined ? { onRejoin } : {})} />;\n}\n\nfunction MeetingRecordBody({\n meeting,\n onRejoin,\n}: {\n meeting: MeetingRecord;\n onRejoin?: () => void;\n}): ReactNode {\n const host = useRequiredMeetHost();\n const record = useMeetingRecord(meeting);\n const [question, setQuestion] = useState(\"\");\n const [tab, setTab] = useState<\"summary\" | \"notes\" | \"transcript\">(\"summary\");\n\n if (record.failure !== null) {\n return (\n <div className=\"mx-meet mx-meet--record\">\n <ErrorBox as=\"div\" className=\"mx-meet__empty\" error={record.failure} operation=\"Open this meeting record\" origin=\"meet/components\">\n <p className=\"mx-meet__empty-title\">This meeting record could not be opened</p>\n <p className=\"mx-meet__empty-body\">{record.failure.message}</p>\n <p className=\"mx-meet__empty-body\">{record.failure.remedy}</p>\n </ErrorBox>\n </div>\n );\n }\n\n if (record.loading || record.record === null) {\n return (\n <div className=\"mx-meet mx-meet--record\">\n <div className=\"mx-meet__empty\" role=\"status\">\n <p className=\"mx-meet__empty-title\">Opening the meeting record…</p>\n <p className=\"mx-meet__empty-body\">\n Reading the summary, the notes and the transcript this meeting left behind.\n </p>\n </div>\n </div>\n );\n }\n\n const bundle = record.record;\n const wrapUp = wrapUpStatus(bundle);\n const blocks = groupTranscript(bundle.transcript, bundle.names);\n const notice = recordingNotice(bundle.recording);\n const fileId = playableRecordingFileId(bundle.recording);\n const attended = bundle.attendees.filter((person) => person.admissionState !== \"denied\");\n const restrictionNotices = summarizeMeetingRecordRestrictions(bundle.restrictions);\n // The server permits the room-pass Q&A only while a guest is in a live\n // meeting. Do not offer a finished-record action that its authorization\n // boundary will always refuse; signed-in members retain durable Q&A.\n const guestFinishedMeeting = host.identity.userId === null && meeting.endedAt !== null;\n const everyRecordPartRefused = (['attendance', 'notes', 'transcript', 'recording'] as const).every(\n (part) => wasRefused(bundle, part),\n );\n const entirelyRestricted =\n everyRecordPartRefused &&\n bundle.attendees.length === 0 &&\n bundle.liveNotes.length === 0 &&\n bundle.transcript.length === 0 &&\n bundle.recording === null &&\n bundle.summary === null &&\n bundle.decisions.length === 0 &&\n bundle.actionItems.length === 0;\n\n if (entirelyRestricted) {\n return (\n <div className=\"mx-meet mx-meet--record\">\n <header className=\"mx-meet__record-head\">\n <div className=\"mx-meet__record-head-inner\">\n <p className=\"mx-meet__record-eyebrow\">Meeting record</p>\n <h1 className=\"mx-meet__record-title\">{meeting.title}</h1>\n <p className=\"mx-meet__record-when\">{meetingWhen(meeting)}</p>\n {onRejoin !== undefined ? (\n <button type=\"button\" className=\"mx-meet__link\" onClick={onRejoin}>\n Open this link again\n </button>\n ) : null}\n </div>\n </header>\n <div className=\"mx-meet__record-body\">\n {restrictionNotices.map((notice) => (\n <div key={notice.parts.join('-')} className=\"mx-meet__record-access\" role=\"status\">\n <p className=\"mx-meet__record-access-title\">About this record</p>\n <p className=\"mx-meet__record-access-message\">{notice.message}</p>\n <p className=\"mx-meet__record-access-remedy\">{notice.remedy}</p>\n </div>\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"mx-meet mx-meet--record\">\n <header className=\"mx-meet__record-head\">\n <div className=\"mx-meet__record-head-inner\">\n <p className=\"mx-meet__record-eyebrow\">Meeting record</p>\n <h1 className=\"mx-meet__record-title\">{meeting.title}</h1>\n <p className=\"mx-meet__record-when\">{meetingWhen(meeting)}</p>\n {onRejoin !== undefined ? (\n <button type=\"button\" className=\"mx-meet__link\" onClick={onRejoin}>\n Open this link again\n </button>\n ) : null}\n </div>\n </header>\n\n <div className=\"mx-meet__record-body\">\n {/* WHAT THIS READER CANNOT SEE, AND WHY. Never an empty section. */}\n {restrictionNotices.map((notice) => (\n <div key={notice.parts.join(\"-\")} className=\"mx-meet__record-access\" role=\"status\">\n <p className=\"mx-meet__record-access-title\">About this record</p>\n <p className=\"mx-meet__record-access-message\">{notice.message}</p>\n <p className=\"mx-meet__record-access-remedy\">{notice.remedy}</p>\n </div>\n ))}\n\n {/* WHO WAS THERE — the durable attendance rows, which outlive the room. */}\n {attended.length === 0 ? (\n /* NOT SILENCE. A refused attendance read used to remove the whole\n section, so the reader could not tell \"nobody\" from \"not shown\". */\n <section className=\"mx-meet__record-section\" aria-label=\"Who attended\">\n <h2 className=\"mx-meet__record-section-title\">Who attended</h2>\n <p className=\"mx-meet__panel-note\">\n {absenceSentence(bundle, \"attendance\", \"Nobody is recorded as having attended.\")}\n </p>\n </section>\n ) : (\n <section className=\"mx-meet__record-section\" aria-label=\"Who attended\">\n <h2 className=\"mx-meet__record-section-title\">Who attended</h2>\n <ul className=\"mx-meet__record-attendees\">\n {attended.map((person) => (\n <li key={person.id} className=\"mx-meet__record-attendee\">\n <Avatar\n name={displayNameFor(bundle.names, person.identity, person.displayName)}\n url={person.avatarUrl}\n size={28}\n />\n <span className=\"mx-meet__person-name\">\n {displayNameFor(bundle.names, person.identity, person.displayName)}\n {person.role === \"host\" ? <span className=\"mx-meet__badge\">Host</span> : null}\n {person.role === \"guest\" ? <span className=\"mx-meet__badge\">Guest</span> : null}\n {/* Attendance establishes an agent's role, not whether it\n captured a transcript. Recording-only meetings can have\n an agent row without any live capture. */}\n {person.isAgent ? (\n <span className=\"mx-meet__badge\">Meeting assistant</span>\n ) : null}\n </span>\n </li>\n ))}\n </ul>\n </section>\n )}\n\n {/* THE RECORDING. `available` plays; anything else states what it is\n doing. There is never a player over a file that does not exist. */}\n {bundle.recording !== null ? (\n <section className=\"mx-meet__record-section mx-meet__recording-card\" aria-label=\"Recording\">\n <h2 className=\"mx-meet__record-section-title\">Recording</h2>\n {fileId !== null ? (\n <>\n <RecordingPlayer fileId={fileId} />\n {notice !== null ? <p className=\"mx-meet__panel-note\">{notice}</p> : null}\n </>\n ) : (\n <p className=\"mx-meet__panel-note\">{notice ?? \"This recording has no file.\"}</p>\n )}\n </section>\n ) : wasRefused(bundle, \"recording\") ? (\n <section className=\"mx-meet__record-section\" aria-label=\"Recording\">\n <h2 className=\"mx-meet__record-section-title\">Recording</h2>\n <p className=\"mx-meet__panel-note\">{REFUSED_ABSENCE}</p>\n </section>\n ) : null}\n\n <nav className=\"mx-meet__record-tabs\" aria-label=\"Meeting record sections\">\n <button\n type=\"button\"\n className={`mx-meet__record-tab${tab === \"summary\" ? \" mx-meet__record-tab--active\" : \"\"}`}\n onClick={() => setTab(\"summary\")}\n aria-pressed={tab === \"summary\"}\n >\n Summary & decisions\n </button>\n <button\n type=\"button\"\n className={`mx-meet__record-tab${tab === \"notes\" ? \" mx-meet__record-tab--active\" : \"\"}`}\n onClick={() => setTab(\"notes\")}\n aria-pressed={tab === \"notes\"}\n >\n Notes as it happened\n </button>\n <button\n type=\"button\"\n className={`mx-meet__record-tab${tab === \"transcript\" ? \" mx-meet__record-tab--active\" : \"\"}`}\n onClick={() => setTab(\"transcript\")}\n aria-pressed={tab === \"transcript\"}\n >\n Transcript\n </button>\n </nav>\n\n {tab === \"summary\" ? (\n <>\n <section className=\"mx-meet__record-section\" aria-label=\"Summary\">\n <h2 className=\"mx-meet__record-section-title\">Summary</h2>\n {/* 🚨 NEVER AN ABSENCE THIS READER CANNOT KNOW (MRI-A16), AND\n NEVER AN ABSENCE THAT IS MERELY EARLY (MRI-A18). This said\n \"No wrap-up was written for this meeting\" under a panel that\n had just refused to read the notes (MRI-C8), and again for the\n ~33 s a perfectly healthy wrap-up job takes to land. Which of\n the five it is comes from `wrapUpStatus`, never from here. */}\n {wrapUp.state === \"written\" ? (\n <p className=\"mx-meet__record-summary\">{bundle.summary?.text}</p>\n ) : wrapUp.state === \"in-progress\" ? (\n <div className=\"mx-meet__panel-note\" role=\"status\">\n <p>{wrapUp.message}</p>\n {/* A LIVE AFFORDANCE, not a spinner over a promise. The\n record view has no realtime feed for a meeting whose room\n is already deleted, so the honest control is the one that\n re-reads the record. */}\n <button type=\"button\" className=\"mx-meet__link\" onClick={record.reload}>\n Check again\n </button>\n </div>\n ) : (\n <p className=\"mx-meet__panel-note\" role={wrapUp.state === \"failed\" ? \"alert\" : undefined}>\n {wrapUp.message}\n </p>\n )}\n </section>\n <NoteList\n title=\"Decisions\"\n notes={bundle.decisions}\n empty={absenceSentence(\n bundle,\n \"notes\",\n \"Nothing was recorded as a decision in this meeting.\",\n )}\n />\n <NoteList\n title=\"Action items\"\n notes={bundle.actionItems}\n empty={absenceSentence(\n bundle,\n \"notes\",\n \"No action items came out of this meeting.\",\n )}\n />\n </>\n ) : null}\n\n {tab === \"notes\" ? (\n <section className=\"mx-meet__record-section\" aria-label=\"Notes as it happened\">\n <h2 className=\"mx-meet__record-section-title\">Notes as it happened</h2>\n {bundle.liveNotes.length === 0 ? (\n <p className=\"mx-meet__panel-note\">\n {absenceSentence(\n bundle,\n \"notes\",\n \"No live notes are available for this meeting.\",\n )}\n </p>\n ) : (\n <ul className=\"mx-meet__notes\">\n {bundle.liveNotes.map((note) => (\n <li key={note.id} className=\"mx-meet__note\">\n {note.window !== null ? (\n <span className=\"mx-meet__badge\">Window {note.window}</span>\n ) : null}\n {note.text}\n </li>\n ))}\n </ul>\n )}\n </section>\n ) : null}\n\n {tab === \"transcript\" ? (\n <section className=\"mx-meet__record-section\" aria-label=\"Transcript\">\n <h2 className=\"mx-meet__record-section-title\">\n Transcript\n <span className=\"mx-meet__record-count\">\n {bundle.transcript.length === 1\n ? \"1 line\"\n : `${bundle.transcript.length} lines`}\n </span>\n </h2>\n {blocks.length === 0 ? (\n <p className=\"mx-meet__panel-note\">\n {absenceSentence(\n bundle,\n \"transcript\",\n \"No transcript is available for this meeting.\",\n )}\n </p>\n ) : (\n <ol className=\"mx-meet__record-transcript\">\n {blocks.map((block) => (\n <li key={block.id} className=\"mx-meet__record-block\">\n <p className=\"mx-meet__record-speaker\">\n {block.speaker}\n <time className=\"mx-meet__record-time\" dateTime={block.startedAt}>\n {clockOf(block.startedAt)}\n </time>\n </p>\n {block.lines.map((line) => (\n <p key={line.id} className=\"mx-meet__record-line\">\n {line.text}\n </p>\n ))}\n </li>\n ))}\n </ol>\n )}\n </section>\n ) : null}\n\n {/* WHAT GUESTS MAY READ, decided where the host can see what there is\n to share. Absent entirely for anyone who is not a host (MRF-1). */}\n <GuestRecordAccessControl meeting={meeting} />\n\n {/* Signed-in members can ask about durable rows after the room closes.\n A guest's room pass deliberately expires for Q&A when the meeting\n ends, even if that guest may still read the shared record. */}\n <section className=\"mx-meet__record-section\" aria-label=\"Ask about this meeting\">\n <h2 className=\"mx-meet__record-section-title\">Ask about this meeting</h2>\n {guestFinishedMeeting ? (\n <p className=\"mx-meet__panel-note\">\n Sign in to ask the assistant about a meeting after it ends.\n </p>\n ) : (\n <>\n <form\n className=\"mx-meet__composer\"\n onSubmit={(event) => {\n event.preventDefault();\n const trimmed = question.trim();\n if (trimmed.length === 0) return;\n void record.ask(trimmed);\n }}\n >\n <input\n className=\"mx-meet__input\"\n value={question}\n onChange={(event) => setQuestion(event.target.value)}\n placeholder=\"What did we decide about the vendor quote?\"\n aria-label=\"Ask about this meeting\"\n />\n <button\n type=\"submit\"\n className=\"mx-meet__primary\"\n disabled={question.trim().length === 0 || record.asking}\n >\n {record.asking ? \"Asking…\" : \"Ask\"}\n </button>\n </form>\n {record.answer !== null ? (\n <p className=\"mx-meet__answer\">{record.answer}</p>\n ) : null}\n {record.coverage !== null ? (\n <p className=\"mx-meet__coverage\">\n Answered from {record.coverage.segmentsUsed} of {record.coverage.segmentsTotal}{\" \"}\n transcript {record.coverage.segmentsTotal === 1 ? \"line\" : \"lines\"}\n {record.coverage.truncated ? \" (the oldest were left out)\" : \"\"}.\n </p>\n ) : null}\n {record.askError !== null ? (\n <ErrorBox as=\"div\" className=\"mx-meet__refusal\" error={record.askError} operation=\"Ask about this meeting\" origin=\"meet/components\">\n <p className=\"mx-meet__refusal-reason\">{record.askError.message}</p>\n <p className=\"mx-meet__refusal-remedy\">{record.askError.remedy}</p>\n </ErrorBox>\n ) : null}\n </>\n )}\n </section>\n </div>\n </div>\n );\n}\n\n/**\n * THE RECORDING, PLAYED THROUGH THE PLATFORM FILE ID (R3).\n *\n * `meet_recordings.file_id` is a PLATFORM file id, never a provider URL — a\n * LiveKit URL is orphaned the day the room is garbage collected, which is the\n * whole reason the column is not `url`. aidream serves the bytes at\n * `GET /files/{id}/download`, and that route is AUTHENTICATED: nothing in this\n * platform ever returns a signed URL (the files law, 2026-08-21/26).\n *\n * 🚨 A BEARER TOKEN IS NOT ENOUGH, and believing it was is what broke this\n * screen. Through 0.4.7 this component built its own `fetch` with only an\n * `authorization` header, so aidream's org-admission middleware answered 400\n * `organization_required` and a 1.38 MB recording that had landed perfectly\n * could not be played by the host who made it (MRI-C8). Every request the\n * package makes now goes through `host.api` (`core/api.ts`), which carries the\n * organization on all of them and cannot be bypassed — `core/api.test.ts`\n * fails the build if a second way to reach aidream appears.\n *\n * It is fetched on a click, never on render: a meeting recording is tens of\n * megabytes and nobody who opened the summary asked to download a video.\n * Every state here is a sentence — loading, failed with a remedy, or playing.\n */\n/** Said after a streaming media error, before a byte retry is attempted. */\nconst STREAM_REFUSED =\n \"Streaming playback did not start, so this recording was downloaded in full instead. \" +\n \"Downloading can take longer, and seeking is unavailable until it finishes.\";\n\nconst PLAYBACK_RETRY_REMEDY =\n \"Reload the page and try again. If it still will not play, ask a meeting host to check the recording.\";\n\nexport function RecordingPlayer(props: { fileId: string }): ReactNode {\n // THE GUARD, not a throw (rule 7c). `<RecordingPlayer>` is a PUBLIC entry\n // component, so a consumer may render it while the provider is still inert —\n // which, since 0.6.0, includes the tick the session read takes (DD-240). It\n // used to call `useRequiredMeetHost()` and throw a package error into the\n // consumer's tree for that tick.\n const host = useMeetHost();\n if (host === null) return <InertNotice what=\"This recording\" />;\n return <RecordingPlayerBody {...props} host={host} />;\n}\n\nfunction RecordingPlayerBody({ fileId, host }: { fileId: string; host: MeetHost }): ReactNode {\n const [media, setMedia] = useState<MeetFileMedia | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<{ message: string; remedy: string } | null>(null);\n\n // A `blob:` url is revoked when this unmounts; a streaming url is not one and\n // must not be revoked. Leaking a blob pins the whole video for the tab's life.\n useEffect(() => {\n if (media === null || media.kind !== \"bytes\") return undefined;\n const url = media.url;\n return () => URL.revokeObjectURL(url);\n }, [media]);\n\n if (media !== null) {\n return (\n <div className=\"mx-meet__record-section\">\n {/* eslint-disable-next-line jsx-a11y/media-has-caption -- the transcript\n below IS the caption track, and it is on the same screen. */}\n <video\n className=\"mx-meet__record-player\"\n src={media.url}\n controls\n preload=\"metadata\"\n onError={() => {\n if (media.kind === \"bytes\") {\n setMedia(null);\n setError({\n message: \"The downloaded recording could not be played.\",\n remedy: PLAYBACK_RETRY_REMEDY,\n });\n return;\n }\n // The media element does not classify codec, network, and browser\n // session failures. Retry authorized bytes without guessing why.\n if (loading) return;\n setLoading(true);\n void (async () => {\n try {\n setMedia({\n url: await host.api.fetchObjectUrl({\n path: fileDownloadPath(fileId),\n operation: \"meet.recording.play\",\n }),\n kind: \"bytes\",\n fallbackReason: STREAM_REFUSED,\n });\n } catch (thrown) {\n const failure = thrown as { message?: string; remedy?: string };\n setMedia(null);\n setError({\n message: failure.message ?? \"The recording could not be played.\",\n remedy: failure.remedy ?? PLAYBACK_RETRY_REMEDY,\n });\n } finally {\n setLoading(false);\n }\n })();\n }}\n />\n {/* 🚨 THE FALLBACK ANNOUNCES ITSELF. When the file had to be downloaded\n in full before playing, the person who waited deserves to know why. */}\n {media.fallbackReason !== null ? (\n <p className=\"mx-meet__panel-note\">{media.fallbackReason}</p>\n ) : null}\n </div>\n );\n }\n\n return (\n <div className=\"mx-meet__record-section\">\n {error !== null ? (\n <ErrorBox as=\"div\" className=\"mx-meet__refusal\" error={error} operation=\"Complete this meeting action\" origin=\"meet/components\">\n <p className=\"mx-meet__refusal-reason\">{error.message}</p>\n <p className=\"mx-meet__refusal-remedy\">{error.remedy}</p>\n </ErrorBox>\n ) : null}\n <button\n type=\"button\"\n className=\"mx-meet__primary mx-meet__record-play\"\n disabled={loading}\n onClick={() => {\n setLoading(true);\n setError(null);\n void (async () => {\n try {\n // 🚨 THROUGH THE ONE CLIENT (MRI-A16). This call used to be a\n // bare `fetch` carrying only a bearer token, and aidream answered\n // 400 `organization_required` — a perfectly landed recording that\n // the host who made it could not play (MRI-C8).\n setMedia(await host.api.fileMedia(fileId, \"meet.recording.play\"));\n } catch (thrown) {\n const failure = thrown as { message?: string; remedy?: string };\n setError({\n message: failure.message ?? \"The recording could not be loaded.\",\n remedy: failure.remedy ?? PLAYBACK_RETRY_REMEDY,\n });\n } finally {\n setLoading(false);\n }\n })();\n }}\n >\n {loading ? \"Loading the recording…\" : \"Play the recording\"}\n </button>\n </div>\n );\n}\n\n/** `10:35` — the clock a person reads beside a line of transcript. */\nfunction clockOf(iso: string): string {\n const at = new Date(iso);\n if (Number.isNaN(at.getTime())) return \"\";\n return at.toLocaleTimeString(undefined, { hour: \"numeric\", minute: \"2-digit\" });\n}\n\n/**\n * THE MEETINGS LIST — live meetings AND the records of finished ones (MRI-D2).\n *\n * A finished meeting is not gone: it is the summary, the decisions, the action\n * items and the transcript behind the same durable link (R3). A list that\n * silently dropped ended meetings is what made every wrap-up unreachable from\n * the product, so an ended row is a first-class row here and its action says\n * what it opens.\n */\nexport function MeetingList({ baseUrl }: { baseUrl?: string }): ReactNode {\n const host = useMeetHost();\n const list = useMeetings();\n if (host === null) return <InertNotice what=\"Your meetings\" />;\n\n if (list.failure !== null) {\n return (\n <ErrorBox as=\"div\" className=\"mx-meet__empty\" error={list.failure} operation=\"List your meetings\" origin=\"meet/components\">\n <p className=\"mx-meet__empty-title\">Your meetings could not be listed</p>\n <p className=\"mx-meet__empty-body\">{list.failure.message}</p>\n <p className=\"mx-meet__empty-body\">{list.failure.remedy}</p>\n </ErrorBox>\n );\n }\n\n if (list.loading) {\n return (\n <div className=\"mx-meet__empty\" role=\"status\">\n <p className=\"mx-meet__empty-title\">Loading your meetings…</p>\n </div>\n );\n }\n\n if (list.meetings.length === 0) {\n return (\n <div className=\"mx-meet__empty\" role=\"status\">\n <p className=\"mx-meet__empty-title\">No meetings yet</p>\n <p className=\"mx-meet__empty-body\">\n Create one above. Its link works before, during and after the meeting — afterwards it\n opens the record.\n </p>\n </div>\n );\n }\n\n const origin =\n baseUrl ?? (typeof window === \"undefined\" ? \"\" : window.location.origin);\n\n return (\n <ul className=\"mx-meet-list\">\n {list.meetings.map((meeting) => {\n const ended = meeting.endedAt !== null;\n return (\n <li key={meeting.id} className=\"mx-meet-list__row\">\n <div className=\"mx-meet-list__main\">\n <span className=\"mx-meet-list__title\">\n {meeting.title}\n {ended ? <span className=\"mx-meet__badge\">Ended</span> : null}\n </span>\n <span className=\"mx-meet-list__when\">{meetingWhen(meeting)}</span>\n </div>\n <a className=\"mx-meet-list__action\" href={meetingLink(origin, meeting.slug)}>\n {ended ? \"Open the record\" : \"Join\"}\n </a>\n </li>\n );\n })}\n </ul>\n );\n}\n","/**\n * PRESENTATION HELPERS specific to a CALL. Pure, tested, and shared by every\n * surface — so a roster line reads the same in the meeting, in the history\n * list, and in the notification.\n *\n * The GENERIC formatters this file used to define — `formatDuration`,\n * `getInitials`, `avatarPaletteIndex` — moved to `@ai-matrx/kit/format` on\n * 2026-09-07 (duplication census H1). They were byte-for-byte duplicated in\n * `@ai-matrx/messaging`, and because two packages claimed them, ~65 host\n * twins across six repos had no correct owner to point at: no surface should\n * take a dependency on the video-calling package to print a duration. Nothing\n * is re-exported from here — import `@ai-matrx/kit/format` directly.\n */\n\nimport type { CallState, MeetParticipant } from \"./types\";\n\n/** \"Ana, Ben and 3 others\" — the roster line, never a raw array join. */\nexport function participantSummary(participants: readonly MeetParticipant[]): string {\n const names = participants.filter((p) => !p.isLocal).map((p) => p.displayName);\n if (names.length === 0) return \"Just you\";\n if (names.length === 1) return names[0] ?? \"\";\n if (names.length === 2) return `${names[0]} and ${names[1]}`;\n return `${names[0]}, ${names[1]} and ${names.length - 2} ${names.length - 2 === 1 ? \"other\" : \"others\"}`;\n}\n\n/** What a settled call says in history. One sentence per terminal state. */\nexport function callStateLabel(state: CallState, outgoing: boolean): string {\n switch (state) {\n case \"dialing\":\n case \"ringing\":\n return outgoing ? \"Calling…\" : \"Incoming call\";\n case \"connecting\":\n return \"Connecting…\";\n case \"active\":\n return \"In call\";\n case \"declined\":\n return outgoing ? \"Declined\" : \"You declined\";\n case \"missed\":\n return outgoing ? \"No answer\" : \"Missed call\";\n case \"busy\":\n return outgoing ? \"On another call\" : \"You were busy\";\n case \"cancelled\":\n return outgoing ? \"Cancelled\" : \"Cancelled by caller\";\n case \"ended\":\n return \"Call ended\";\n case \"failed\":\n return \"Call failed\";\n default:\n return \"Call\";\n }\n}\n\n/** \"2 waiting\" for the lobby badge — plural handled once, not per surface. */\nexport function countLabel(count: number, singular: string, plural = `${singular}s`): string {\n return `${count} ${count === 1 ? singular : plural}`;\n}\n","\"use client\";\n\n/**\n * INLINED SVGs — no icon-library dependency, ever (C19).\n *\n * The tap-target precedent: ~60 buttons, all inlined, a fraction of a percent\n * of bloat and zero version-skew risk. These are Lucide-shaped paths, adapted;\n * they inherit `currentColor` so the token contract, not an icon prop, decides\n * every color.\n */\n\nimport type { SVGProps } from \"react\";\n\ntype IconProps = SVGProps<SVGSVGElement>;\n\nfunction Icon({ children, ...props }: IconProps): React.ReactElement {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n {...props}\n >\n {children}\n </svg>\n );\n}\n\nexport function MicIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\" />\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <path d=\"M12 19v3\" />\n </Icon>\n );\n}\n\nexport function MicOffIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M2 2l20 20\" />\n <path d=\"M9 9v3a3 3 0 0 0 5.12 2.12\" />\n <path d=\"M15 9.34V5a3 3 0 0 0-5.94-.6\" />\n <path d=\"M19 10v2a7 7 0 0 1-.11 1.23M5 10v2a7 7 0 0 0 11 5.66\" />\n <path d=\"M12 19v3\" />\n </Icon>\n );\n}\n\nexport function CameraIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"m23 7-7 5 7 5V7Z\" />\n <rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\" />\n </Icon>\n );\n}\n\nexport function CameraOffIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M2 2l20 20\" />\n <path d=\"M10.66 5H14a2 2 0 0 1 2 2v3.34l1 1L23 7v10\" />\n <path d=\"M16 16a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h2\" />\n </Icon>\n );\n}\n\nexport function ScreenShareIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"14\" rx=\"2\" />\n <path d=\"M8 21h8M12 17v4\" />\n <path d=\"M12 13V8m0 0-2.5 2.5M12 8l2.5 2.5\" />\n </Icon>\n );\n}\n\nexport function PhoneIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6A19.79 19.79 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.9.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92Z\" />\n </Icon>\n );\n}\n\nexport function PhoneOffIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M2 2l20 20\" />\n <path d=\"M10.68 13.31a16 16 0 0 0 3.41 2.6l1.27-1.27a2 2 0 0 1 2.11-.45c.9.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.42 19.42 0 0 1-3.33-2.67\" />\n <path d=\"M5.53 5.53A19.79 19.79 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91\" />\n </Icon>\n );\n}\n\nexport function HandIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M18 11V6a2 2 0 0 0-4 0v5\" />\n <path d=\"M14 10V4a2 2 0 0 0-4 0v7\" />\n <path d=\"M10 10.5V6a2 2 0 0 0-4 0v8\" />\n <path d=\"M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2a8 8 0 0 1-8-8v-1a2 2 0 1 1 4 0\" />\n </Icon>\n );\n}\n\nexport function ChatIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2Z\" />\n </Icon>\n );\n}\n\nexport function PeopleIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2\" />\n <circle cx=\"9\" cy=\"7\" r=\"4\" />\n <path d=\"M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75\" />\n </Icon>\n );\n}\n\nexport function RecordIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"8\" fill=\"currentColor\" stroke=\"none\" />\n </Icon>\n );\n}\n\nexport function SparklesIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M12 3l1.9 4.6L18.5 9.5l-4.6 1.9L12 16l-1.9-4.6L5.5 9.5l4.6-1.9L12 3Z\" />\n <path d=\"M19 15l.9 2.1 2.1.9-2.1.9-.9 2.1-.9-2.1-2.1-.9 2.1-.9L19 15Z\" />\n </Icon>\n );\n}\n\nexport function LockIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <rect x=\"4\" y=\"10\" width=\"16\" height=\"11\" rx=\"2\" />\n <path d=\"M8 10V7a4 4 0 0 1 8 0v3\" />\n </Icon>\n );\n}\n\nexport function LayoutIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" />\n <path d=\"M3 9h18M9 21V9\" />\n </Icon>\n );\n}\n\nexport function SettingsIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.6a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z\" />\n </Icon>\n );\n}\n\nexport function CheckIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M20 6 9 17l-5-5\" />\n </Icon>\n );\n}\n\nexport function CloseIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </Icon>\n );\n}\n\nexport function PinIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M12 17v5\" />\n <path d=\"M9 2h6l-1 6 3.5 3.5V14H6.5v-2.5L10 8 9 2Z\" />\n </Icon>\n );\n}\n\nexport function WifiLowIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M12 20h.01\" />\n <path d=\"M8.5 16.5a5 5 0 0 1 7 0\" />\n </Icon>\n );\n}\n\n/* Meet wave 2 */\n\nexport function SmileIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M8 14s1.5 2 4 2 4-2 4-2\" />\n <line x1=\"9\" x2=\"9.01\" y1=\"9\" y2=\"9\" />\n <line x1=\"15\" x2=\"15.01\" y1=\"9\" y2=\"9\" />\n </Icon>\n );\n}\n\nexport function MoreIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"19\" cy=\"12\" r=\"1\" />\n <circle cx=\"5\" cy=\"12\" r=\"1\" />\n </Icon>\n );\n}\n\nexport function SearchIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </Icon>\n );\n}\n\nexport function KeyboardIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M10 8h.01M12 12h.01M14 8h.01M16 12h.01M18 8h.01M6 8h.01M7 16h10M8 12h.01\" />\n <rect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\" />\n </Icon>\n );\n}\n\nexport function SpotlightIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M12 2 15 8.5 22 9.3 17 14 18.2 21 12 17.6 5.8 21 7 14 2 9.3 9 8.5Z\" />\n </Icon>\n );\n}\n\nexport function SignalIcon({ bars, ...props }: IconProps & { bars: 0 | 1 | 2 | 3 }): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M4 20v-2\" opacity={bars >= 1 ? 1 : 0.3} />\n <path d=\"M10 20v-6\" opacity={bars >= 2 ? 1 : 0.3} />\n <path d=\"M16 20V9\" opacity={bars >= 3 ? 1 : 0.3} />\n <path d=\"M22 20V4\" opacity={bars >= 3 ? 1 : 0.3} />\n </Icon>\n );\n}\n\nexport function SpeakerIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M11 5 6 9H2v6h4l5 4V5Z\" />\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\" />\n <path d=\"M19.07 4.93a10 10 0 0 1 0 14.14\" />\n </Icon>\n );\n}\n\nexport function FlagIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z\" />\n <line x1=\"4\" x2=\"4\" y1=\"22\" y2=\"15\" />\n </Icon>\n );\n}\n\nexport function PencilIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z\" />\n </Icon>\n );\n}\n","/**\n * THE MESSAGING SEAM — a call invitation is an ACTIONABLE MESSAGE (D8).\n *\n * `@ai-matrx/messaging` deliberately knows nothing about meetings; its action\n * registry exists so packages like this one can add a kind without messaging\n * learning about them. This file is that registration, and it is the whole\n * coupling between the two packages.\n *\n * Why an invitation is a message and not only a ring: a ring is EPHEMERAL. If\n * you were away from your desk, a broadcast that expired is gone, and \"someone\n * tried to reach me\" is exactly the information you most needed. The message is\n * the durable half — it is still in the thread tomorrow, with the outcome\n * stamped on it.\n *\n * 🚨 **THE PAYLOAD IS NOT AUTHORIZATION.** The chip's payload says what was\n * ASKED, never what is ALLOWED. The handler re-resolves the invite through the\n * repository (an auth-checked RPC) before it joins anything. Trusting the\n * payload would turn any message anyone can send into a room grant.\n *\n * Idempotence is the registry's, not ours: two tabs and a double tap settle\n * ONCE and share one receipt.\n */\n\nimport type { ActionHandler, ActionReceipt } from \"@ai-matrx/messaging\";\nimport type { CallCenter } from \"./calls\";\nimport { MeetError } from \"./errors\";\nimport type { MeetRepository } from \"./repository\";\nimport { asCallId, asUserId, type CallInvite, type CallMode } from \"./types\";\n\nexport const CALL_INVITE_KIND = \"meet.call-invite\";\nexport const CALL_INVITE_VERSION = 1;\n\nexport interface CallInvitePayload {\n readonly invite_id: string;\n readonly room_name: string;\n readonly mode: CallMode;\n readonly caller_name: string;\n readonly expires_at: string;\n}\n\n/** The `action_data` a caller attaches to the invitation message. */\nexport function callInviteAction(invite: CallInvite): {\n readonly kind: string;\n readonly version: number;\n readonly payload: CallInvitePayload;\n} {\n return {\n kind: CALL_INVITE_KIND,\n version: CALL_INVITE_VERSION,\n payload: {\n invite_id: invite.id,\n room_name: invite.roomName,\n mode: invite.mode,\n caller_name: invite.callerName,\n expires_at: invite.expiresAt,\n },\n };\n}\n\n/** The message body. Readable on a surface that cannot render the chips. */\nexport function callInviteText(invite: CallInvite): string {\n return invite.mode === \"video\"\n ? `${invite.callerName} started a video call`\n : `${invite.callerName} started an audio call`;\n}\n\nexport interface CallInviteHandlerOptions {\n calls: CallCenter;\n repository: MeetRepository;\n /** Called after a successful accept, with the room to enter. */\n onJoin: (invite: CallInvite) => void | Promise<void>;\n now?: (() => number) | undefined;\n}\n\nexport function createCallInviteHandler(\n options: CallInviteHandlerOptions,\n): ActionHandler<CallInvitePayload> {\n const now = options.now ?? (() => Date.now());\n\n return {\n kind: CALL_INVITE_KIND,\n versions: [CALL_INVITE_VERSION],\n choices: (payload) => {\n // An EXPIRED invite renders no chips. Offering \"Join\" for a call that\n // ended twenty minutes ago is a dead end with a friendly face.\n if (Date.parse(payload.expires_at) < now()) return [];\n return [\n { id: \"join\", label: payload.mode === \"video\" ? \"Join video\" : \"Join call\", tone: \"primary\" },\n { id: \"decline\", label: \"Decline\", tone: \"neutral\" },\n ];\n },\n summarize: (payload) =>\n payload.mode === \"video\"\n ? `${payload.caller_name} started a video call`\n : `${payload.caller_name} started an audio call`,\n execute: async (payload, context): Promise<ActionReceipt> => {\n const settledAt = new Date(now()).toISOString();\n const inviteId = asCallId(payload.invite_id);\n\n // RE-RESOLVE. The payload told us what to look for; the database tells us\n // whether it is still true and whether this actor may act on it.\n // `context.actorId` is messaging's branded UserId; ours is a distinct\n // brand over the same string. Re-branding through the constructor is the\n // honest crossing — a cast between two brands would compile today and\n // hide a genuine mismatch the day either package changes its identity.\n const pending = await options.repository.pendingInvites(asUserId(String(context.actorId)));\n const live = pending.find((invite) => invite.id === inviteId) ?? null;\n\n if (live === null) {\n return {\n kind: CALL_INVITE_KIND,\n messageId: context.messageId,\n actorId: context.actorId,\n outcome: \"unavailable\",\n label: \"This call has ended\",\n settledAt,\n detail:\n \"The invite is no longer ringing — it was answered elsewhere, cancelled, or it \" +\n \"timed out. The chips are replaced by the outcome rather than left clickable.\",\n };\n }\n\n if (context.choice === \"decline\") {\n await options.calls.decline(inviteId);\n return {\n kind: CALL_INVITE_KIND,\n messageId: context.messageId,\n actorId: context.actorId,\n outcome: \"declined\",\n label: \"Declined\",\n settledAt,\n };\n }\n\n const accepted = await options.calls.accept(inviteId, live.mode);\n await options.onJoin(accepted);\n return {\n kind: CALL_INVITE_KIND,\n messageId: context.messageId,\n actorId: context.actorId,\n outcome: \"applied\",\n label: \"Joined\",\n settledAt,\n };\n },\n };\n}\n\n/**\n * A meeting invitation — the scheduled twin. Deliberately NOT the same kind: a\n * scheduled meeting's chip must never say \"Join call\" three days early, and a\n * receiver that only understands calls must render NOTHING for it rather than a\n * button it cannot honor.\n */\nexport const MEETING_INVITE_KIND = \"meet.meeting-invite\";\nexport const MEETING_INVITE_VERSION = 1;\n\nexport interface MeetingInvitePayload {\n readonly meeting_id: string;\n readonly slug: string;\n readonly title: string;\n readonly scheduled_for: string | null;\n readonly link: string;\n}\n\nexport function meetingInviteAction(payload: MeetingInvitePayload): {\n readonly kind: string;\n readonly version: number;\n readonly payload: MeetingInvitePayload;\n} {\n return { kind: MEETING_INVITE_KIND, version: MEETING_INVITE_VERSION, payload };\n}\n\nexport interface MeetingInviteHandlerOptions {\n onOpen: (payload: MeetingInvitePayload) => void | Promise<void>;\n now?: (() => number) | undefined;\n}\n\nexport function createMeetingInviteHandler(\n options: MeetingInviteHandlerOptions,\n): ActionHandler<MeetingInvitePayload> {\n const now = options.now ?? (() => Date.now());\n return {\n kind: MEETING_INVITE_KIND,\n versions: [MEETING_INVITE_VERSION],\n // A DURABLE LINK NEVER EXPIRES (R3) — the chip stays useful after the\n // meeting too, because that is when people go looking for the notes.\n choices: () => [{ id: \"open\", label: \"Open meeting\", tone: \"primary\" }],\n summarize: (payload) =>\n payload.scheduled_for === null\n ? payload.title\n : `${payload.title} — ${payload.scheduled_for}`,\n execute: async (payload, context): Promise<ActionReceipt> => {\n if (payload.slug.length === 0) {\n throw new MeetError(\n \"invalid-response\",\n \"meet.meeting-invite: the payload carries no slug\",\n \"A meeting invitation without a durable slug cannot be opened. Fix the sender; \" +\n \"never synthesize a link on the receiving side.\",\n );\n }\n await options.onOpen(payload);\n return {\n kind: MEETING_INVITE_KIND,\n messageId: context.messageId,\n actorId: context.actorId,\n outcome: \"applied\",\n label: \"Opened\",\n settledAt: new Date(now()).toISOString(),\n };\n },\n };\n}\n","/**\n * AFTER THE MEETING (Meet wave 3) — the pure pieces every client needs once the\n * room is gone: the attendance report, the transcript and notes as documents,\n * a moment in the transcript as a moment in the recording, search within one\n * transcript, and the two server calls behind the recap email and the saved\n * chat.\n *\n * Nothing here computes MEANING (same rule as `record.ts`): the summary,\n * decisions and action items are the wrap-up's durable rows; this file only\n * arranges, measures and formats them. Every function is framework-free so a\n * worker, a test and a browser produce byte-identical exports.\n */\n\nimport { formatDurationMs } from \"@ai-matrx/kit/format\";\nimport { readServerRefusal } from \"./ai\";\nimport type { MeetApi } from \"./api\";\nimport { MeetError } from \"./errors\";\nimport { displayNameFor, type NameBook } from \"./names\";\nimport type { MeetingRecordBundle } from \"./record\";\nimport { chatFromRow } from \"./room-events\";\nimport type { RoomChatMessage } from \"./store\";\nimport { MEET_ROUTES, meetingPath, ROOM_TOKEN_HEADER } from \"./tokens\";\nimport type {\n MeetingAttendee,\n MeetingId,\n MeetingNote,\n MeetingRecord,\n RecordingRecord,\n TranscriptSegment,\n} from \"./types\";\n\n/* ─────────────────────────── Attendance ─────────────────────────── */\n\n/**\n * Who someone was, in the words an attendance report uses. `signed-in guest` is\n * an account from outside the meeting's organization that followed the link;\n * `guest` has no account at all.\n */\nexport type AttendanceKind = \"host\" | \"cohost\" | \"member\" | \"signed-in guest\" | \"guest\" | \"assistant\";\n\nexport interface AttendanceRow {\n readonly id: string;\n readonly identity: string;\n readonly name: string;\n readonly userId: string | null;\n readonly kind: AttendanceKind;\n /** First time they were in the room; null when they knocked and never came in. */\n readonly joinedAt: string | null;\n /** When they left; null while still in the room or when the leave was never recorded. */\n readonly leftAt: string | null;\n /**\n * Time in the room. A missing `leftAt` is measured to the meeting's end —\n * the room closed around them — and `null` only when neither is known.\n */\n readonly durationMs: number | null;\n /** True when `durationMs` was measured to the meeting's end, not a recorded leave. */\n readonly durationToEnd: boolean;\n readonly admission: MeetingAttendee[\"admissionState\"];\n}\n\nfunction kindOf(person: MeetingAttendee): AttendanceKind {\n if (person.isAgent) return \"assistant\";\n if (person.role === \"host\") return \"host\";\n if (person.role === \"cohost\") return \"cohost\";\n if (person.role === \"guest\") return person.userId !== null ? \"signed-in guest\" : \"guest\";\n return \"member\";\n}\n\nfunction ms(iso: string | null): number | null {\n if (iso === null) return null;\n const at = new Date(iso).getTime();\n return Number.isNaN(at) ? null : at;\n}\n\n/**\n * The attendance report of ONE meeting, host first then by arrival. People who\n * knocked and were never let in are kept (with no join time) — \"who asked to\n * come in\" is part of the record — but a denied knock has no duration.\n */\nexport function attendanceReport(\n meeting: MeetingRecord,\n attendees: readonly MeetingAttendee[],\n names: NameBook = {},\n): readonly AttendanceRow[] {\n const end = ms(meeting.endedAt);\n const rows = attendees.map((person): AttendanceRow => {\n const joined = ms(person.joinedAt);\n const left = ms(person.leftAt);\n const until = left ?? end;\n const duration = joined !== null && until !== null && until >= joined ? until - joined : null;\n return {\n id: person.id,\n identity: person.identity,\n name: displayNameFor(names, person.identity, person.displayName),\n userId: person.userId,\n kind: kindOf(person),\n joinedAt: person.joinedAt,\n leftAt: person.leftAt,\n durationMs: duration,\n durationToEnd: duration !== null && left === null,\n admission: person.admissionState,\n };\n });\n const rank: Record<AttendanceKind, number> = {\n host: 0,\n cohost: 1,\n member: 2,\n \"signed-in guest\": 3,\n guest: 4,\n assistant: 5,\n };\n return rows.sort((a, b) => {\n if (rank[a.kind] !== rank[b.kind]) return rank[a.kind] - rank[b.kind];\n return (ms(a.joinedAt) ?? Number.MAX_SAFE_INTEGER) - (ms(b.joinedAt) ?? Number.MAX_SAFE_INTEGER);\n });\n}\n\n/** Headline numbers for the top of a report. The assistant is never a person. */\nexport function attendanceTotals(rows: readonly AttendanceRow[]): {\n readonly people: number;\n readonly guests: number;\n readonly neverAdmitted: number;\n readonly averageMs: number | null;\n} {\n const humans = rows.filter((row) => row.kind !== \"assistant\");\n const attended = humans.filter((row) => row.joinedAt !== null);\n const timed = attended.filter((row) => row.durationMs !== null);\n return {\n people: attended.length,\n guests: attended.filter((row) => row.kind === \"guest\" || row.kind === \"signed-in guest\").length,\n neverAdmitted: humans.filter((row) => row.joinedAt === null).length,\n averageMs:\n timed.length === 0\n ? null\n : Math.round(timed.reduce((sum, row) => sum + (row.durationMs ?? 0), 0) / timed.length),\n };\n}\n\nfunction csvCell(value: string | number | null): string {\n if (value === null) return \"\";\n const text = String(value);\n return /[\",\\n\\r]/.test(text) ? `\"${text.replace(/\"/g, '\"\"')}\"` : text;\n}\n\nexport const ATTENDANCE_CSV_HEADER = [\n \"Meeting\",\n \"Meeting started\",\n \"Name\",\n \"Attended as\",\n \"Joined\",\n \"Left\",\n \"Minutes in the meeting\",\n \"Admission\",\n] as const;\n\n/**\n * CSV for a spreadsheet: one header row, one row per person, ISO timestamps (a\n * spreadsheet parses them; a formatted local clock loses the zone). Several\n * meetings — a series — concatenate with one header.\n */\nexport function attendanceCsv(\n reports: readonly { meeting: MeetingRecord; rows: readonly AttendanceRow[] }[],\n): string {\n const lines = [ATTENDANCE_CSV_HEADER.join(\",\")];\n for (const { meeting, rows } of reports) {\n for (const row of rows) {\n lines.push(\n [\n meeting.title,\n meeting.startedAt ?? meeting.scheduledFor,\n row.name,\n row.kind,\n row.joinedAt,\n row.leftAt,\n row.durationMs === null ? null : Math.round(row.durationMs / 6_000) / 10,\n row.admission,\n ]\n .map(csvCell)\n .join(\",\"),\n );\n }\n }\n return `${lines.join(\"\\r\\n\")}\\r\\n`;\n}\n\n/* ───────────────────── A moment in the recording ───────────────────── */\n\n/**\n * Where an instant of the meeting falls in the RECORDING, in milliseconds from\n * its start — or `null` when the recording does not cover it (a recording is\n * often a few minutes of a longer meeting). Never a clamp: seeking a line that\n * was said before recording began to 0:00 would play the wrong words.\n */\nexport function recordingOffsetMs(at: string, recording: RecordingRecord | null): number | null {\n if (recording === null || recording.state !== \"available\") return null;\n const start = ms(recording.startedAt);\n const moment = ms(at);\n if (start === null || moment === null || moment < start) return null;\n const end = ms(recording.endedAt);\n if (end !== null && moment > end) return null;\n return moment - start;\n}\n\n/** `m:ss` or `h:mm:ss` — a position in a recording or a meeting. */\nexport function clockPosition(offsetMs: number): string {\n const total = Math.max(0, Math.floor(offsetMs / 1000));\n const h = Math.floor(total / 3600);\n const m = Math.floor((total % 3600) / 60);\n const s = total % 60;\n const ss = String(s).padStart(2, \"0\");\n return h > 0 ? `${h}:${String(m).padStart(2, \"0\")}:${ss}` : `${m}:${ss}`;\n}\n\n/* ───────────────────── Search within one transcript ───────────────────── */\n\nexport interface TranscriptMatch {\n readonly segmentId: string;\n /** [start, end) character ranges inside the segment's text, in order. */\n readonly ranges: readonly (readonly [number, number])[];\n}\n\n/**\n * Case-insensitive search of the transcript text AND the speaker's\n * name. Returns matches in transcript order. An empty query matches nothing.\n */\nexport function searchTranscript(\n segments: readonly TranscriptSegment[],\n query: string,\n names: NameBook = {},\n): readonly TranscriptMatch[] {\n const needle = fold(query.trim());\n if (needle.length === 0) return [];\n const out: TranscriptMatch[] = [];\n for (const segment of segments) {\n const hay = fold(segment.text);\n const ranges: [number, number][] = [];\n let from = 0;\n for (;;) {\n const at = hay.indexOf(needle, from);\n if (at < 0) break;\n ranges.push([at, at + needle.length]);\n from = at + needle.length;\n }\n const speaker = fold(displayNameFor(names, segment.identity, segment.speaker));\n if (ranges.length > 0 || speaker.includes(needle)) {\n out.push({ segmentId: segment.id, ranges });\n }\n }\n return out;\n}\n\n/** Lowercase, strip combining marks; length-preserving for the Latin range. */\nfunction fold(value: string): string {\n return value\n .normalize(\"NFD\")\n .replace(/[̀-ͯ]/g, (mark) => (mark.length === 1 ? \"\" : mark))\n .toLowerCase();\n}\n\n/* ───────────────────────── Documents ───────────────────────── */\n\nexport type TranscriptFormat = \"txt\" | \"md\" | \"vtt\";\n\ninterface ExportOptions {\n readonly names?: NameBook;\n /** Timestamps as a clock of day (default) or offsets from `zero`. */\n readonly locale?: string;\n readonly timeZone?: string;\n}\n\nfunction clockOfDay(iso: string, options: ExportOptions): string {\n const at = new Date(iso);\n if (Number.isNaN(at.getTime())) return \"\";\n return at.toLocaleTimeString(options.locale, {\n hour: \"numeric\",\n minute: \"2-digit\",\n second: \"2-digit\",\n ...(options.timeZone !== undefined ? { timeZone: options.timeZone } : {}),\n });\n}\n\nfunction vttStamp(offsetMs: number): string {\n const total = Math.max(0, Math.round(offsetMs));\n const h = Math.floor(total / 3_600_000);\n const m = Math.floor((total % 3_600_000) / 60_000);\n const s = Math.floor((total % 60_000) / 1000);\n const milli = total % 1000;\n return `${String(h).padStart(2, \"0\")}:${String(m).padStart(2, \"0\")}:${String(s).padStart(2, \"0\")}.${String(milli).padStart(3, \"0\")}`;\n}\n\n/**\n * The transcript as a document. `txt` and `md` group consecutive lines by one\n * speaker with the clock of day; `vtt` is WebVTT cued from the recording's\n * start when a recording exists (so it plays as captions over it), otherwise\n * from the meeting's start — and a cue ends where the next line begins.\n */\nexport function transcriptDocument(\n bundle: Pick<MeetingRecordBundle, \"meeting\" | \"transcript\" | \"recording\" | \"names\">,\n format: TranscriptFormat,\n options: ExportOptions = {},\n): string {\n const names = options.names ?? bundle.names;\n const lines = bundle.transcript.filter((line) => line.text.trim().length > 0);\n const speaker = (line: TranscriptSegment) => displayNameFor(names, line.identity, line.speaker);\n\n if (format === \"vtt\") {\n const zeroIso =\n bundle.recording?.state === \"available\" && bundle.recording.startedAt !== null\n ? bundle.recording.startedAt\n : (bundle.meeting.startedAt ?? lines[0]?.startedAt ?? null);\n const zero = ms(zeroIso) ?? 0;\n const cues = [\"WEBVTT\", \"\"];\n lines.forEach((line, index) => {\n const start = (ms(line.startedAt) ?? zero) - zero;\n if (start < 0) return;\n const next = lines[index + 1];\n const nextStart = next !== undefined ? (ms(next.startedAt) ?? zero) - zero : start + 4000;\n const end = Math.max(start + 500, Math.min(nextStart, start + 10_000));\n cues.push(`${vttStamp(start)} --> ${vttStamp(end)}`);\n cues.push(`<v ${speaker(line).replace(/[<>]/g, \"\")}>${line.text.replace(/-->/g, \"->\")}`);\n cues.push(\"\");\n });\n return cues.join(\"\\n\");\n }\n\n const out: string[] = [];\n const title = bundle.meeting.title;\n out.push(format === \"md\" ? `# ${title} — transcript` : `${title} — transcript`);\n out.push(\"\");\n let last: string | null = null;\n for (const line of lines) {\n if (line.identity !== last) {\n if (last !== null) out.push(\"\");\n const who = speaker(line);\n const clock = clockOfDay(line.startedAt, options);\n out.push(format === \"md\" ? `**${who}** · ${clock}` : `${who} (${clock})`);\n last = line.identity;\n }\n out.push(line.text.trim());\n }\n if (lines.length === 0) out.push(\"No transcript was captured for this meeting.\");\n return `${out.join(\"\\n\")}\\n`;\n}\n\nfunction bullet(note: MeetingNote): string {\n const owner = note.assigneeDisplayName !== null ? ` — ${note.assigneeDisplayName}` : \"\";\n return `- ${note.text.trim()}${owner}`;\n}\n\n/**\n * The meeting's notes as Markdown: when, who attended, the summary, decisions\n * and action items (with owners), and the link back. What a person pastes into\n * a doc or an email; also the source for PDF / Word export.\n */\nexport function notesDocument(\n bundle: Pick<\n MeetingRecordBundle,\n \"meeting\" | \"summary\" | \"decisions\" | \"actionItems\" | \"attendees\" | \"names\"\n >,\n options: { readonly link?: string | null; readonly when?: string | null } = {},\n): string {\n const out: string[] = [`# ${bundle.meeting.title}`, \"\"];\n if (options.when) out.push(`_${options.when}_`, \"\");\n const people = bundle.attendees\n .filter((person) => !person.isAgent && person.joinedAt !== null)\n .map((person) => displayNameFor(bundle.names, person.identity, person.displayName));\n if (people.length > 0) out.push(`**Attended:** ${people.join(\", \")}`, \"\");\n out.push(\"## Summary\", \"\", bundle.summary?.text.trim() || \"No summary was written.\", \"\");\n out.push(\"## Decisions\", \"\");\n out.push(...(bundle.decisions.length > 0 ? bundle.decisions.map(bullet) : [\"None recorded.\"]), \"\");\n out.push(\"## Action items\", \"\");\n out.push(\n ...(bundle.actionItems.length > 0 ? bundle.actionItems.map(bullet) : [\"None recorded.\"]),\n \"\",\n );\n if (options.link) out.push(`[Open the meeting record](${options.link})`, \"\");\n return out.join(\"\\n\");\n}\n\n/** How long the meeting ran, in words (\"42 minutes\"), or null when unknown. */\nexport function meetingLength(meeting: MeetingRecord): string | null {\n const start = ms(meeting.startedAt);\n const end = ms(meeting.endedAt);\n if (start === null || end === null || end < start) return null;\n return formatDurationMs(end - start, { style: \"long\" });\n}\n\n/* ───────────────────────── Saved chat ───────────────────────── */\n\nexport interface MeetingChatHistory {\n readonly messages: readonly RoomChatMessage[];\n /** The server's refusal, in its words, when the history could not be read. */\n readonly refusal: { readonly message: string; readonly remedy: string } | null;\n}\n\n/**\n * The saved chat of a finished meeting (`GET /v1/meet/chat`). Private messages\n * are never saved, by design, so they are never here. A refusal is returned as\n * data — the record still renders everything else.\n */\nexport async function loadMeetingChat(\n api: MeetApi,\n meetingId: MeetingId,\n roomToken: string | null = null,\n): Promise<MeetingChatHistory> {\n const operation = \"meet.loadMeetingChat\";\n let response: Response;\n try {\n response = await api.request({\n path: `${MEET_ROUTES.chat}?meeting_id=${encodeURIComponent(meetingId)}`,\n method: \"GET\",\n operation,\n requireAuth: roomToken === null,\n ...(roomToken !== null ? { headers: { [ROOM_TOKEN_HEADER]: roomToken } } : {}),\n });\n } catch (error) {\n return {\n messages: [],\n refusal: {\n message: `The chat could not be read (${(error as Error).message}).`,\n remedy: (error as { remedy?: string }).remedy ?? \"Reload the page.\",\n },\n };\n }\n if (!response.ok) {\n let body: unknown = null;\n try {\n body = await response.json();\n } catch {\n body = null;\n }\n const said = readServerRefusal(body);\n return {\n messages: [],\n refusal: {\n message: said?.reason ?? `The chat could not be read (the server answered ${response.status}).`,\n remedy: said?.remedy || \"Reload the page.\",\n },\n };\n }\n const payload = (await response.json()) as { messages?: unknown };\n const rows = Array.isArray(payload.messages) ? payload.messages : [];\n return {\n messages: rows\n .map((row) =>\n typeof row === \"object\" && row !== null ? chatFromRow(row as Record<string, unknown>) : null,\n )\n .filter((message): message is RoomChatMessage => message !== null),\n refusal: null,\n };\n}\n\n/* ───────────────────────── The recap email ───────────────────────── */\n\n/** One person the recap can go to, as the server resolved them. */\nexport interface FollowUpRecipient {\n /** Stable key for the choice: `user:<id>` or `email:<address>`. */\n readonly key: string;\n readonly name: string;\n /** The address, when this reader may see it (the host sees their guests'). */\n readonly email: string | null;\n readonly userId: string | null;\n /** `invitee`, `attendee` or both — where the server found them. */\n readonly sources: readonly (\"invitee\" | \"attendee\")[];\n /** False when the server has no way to reach them (no account, no address). */\n readonly reachable: boolean;\n}\n\n/** The draft the host reviews. The text is the wrap-up's own, arranged. */\nexport interface FollowUpDraft {\n readonly subject: string;\n readonly body: string;\n readonly recipients: readonly FollowUpRecipient[];\n /** False while the wrap-up has not been written — the draft says so. */\n readonly wrapUpWritten: boolean;\n /** When a recap for this meeting was last sent, and to how many. */\n readonly lastSent: { readonly at: string; readonly count: number } | null;\n}\n\nexport interface FollowUpSendResult {\n readonly dryRun: boolean;\n /** Recipients the send queued (or, on a dry run, would queue). */\n readonly queued: readonly string[];\n /** Recipient keys skipped, each with the reason. */\n readonly skipped: readonly { readonly key: string; readonly reason: string }[];\n}\n\nasync function refusalOf(response: Response, operation: string): Promise<MeetError> {\n let body: unknown = null;\n try {\n body = await response.json();\n } catch {\n body = null;\n }\n const said = readServerRefusal(body);\n return new MeetError(\n response.status === 403 || response.status === 401\n ? \"forbidden\"\n : response.status === 404\n ? \"not-found\"\n : response.status === 409\n ? \"conflict\"\n : \"transport\",\n `${operation}: ${said?.reason ?? `the server answered ${response.status}`}`,\n said?.remedy || \"Nothing was sent. Try again.\",\n );\n}\n\nfunction asRecipient(row: Record<string, unknown>): FollowUpRecipient {\n const sources = Array.isArray(row[\"sources\"]) ? (row[\"sources\"] as string[]) : [];\n return {\n key: String(row[\"key\"] ?? \"\"),\n name: String(row[\"name\"] ?? \"\"),\n email: typeof row[\"email\"] === \"string\" ? row[\"email\"] : null,\n userId: typeof row[\"user_id\"] === \"string\" ? row[\"user_id\"] : null,\n sources: sources.filter((s): s is \"invitee\" | \"attendee\" => s === \"invitee\" || s === \"attendee\"),\n reachable: row[\"reachable\"] !== false,\n };\n}\n\n/** The recap draft for a finished meeting. The host, a co-host or an editor. */\nexport async function loadFollowUpDraft(api: MeetApi, meetingId: MeetingId): Promise<FollowUpDraft> {\n const operation = \"meet.loadFollowUpDraft\";\n const response = await api.request({\n path: meetingPath(MEET_ROUTES.meetingFollowUp, meetingId),\n method: \"GET\",\n requireAuth: true,\n operation,\n });\n if (!response.ok) throw await refusalOf(response, operation);\n const body = (await response.json()) as Record<string, unknown>;\n const last = body[\"last_sent\"] as Record<string, unknown> | null | undefined;\n return {\n subject: String(body[\"subject\"] ?? \"\"),\n body: String(body[\"body\"] ?? \"\"),\n recipients: (Array.isArray(body[\"recipients\"]) ? body[\"recipients\"] : []).map((row) =>\n asRecipient(row as Record<string, unknown>),\n ),\n wrapUpWritten: body[\"wrap_up_written\"] === true,\n lastSent:\n last && typeof last[\"at\"] === \"string\"\n ? { at: last[\"at\"], count: typeof last[\"count\"] === \"number\" ? last[\"count\"] : 0 }\n : null,\n };\n}\n\n/**\n * Send the recap the host reviewed. `dryRun` resolves every recipient and\n * renders every email but queues nothing — how a test proves the path without\n * mailing a real inbox. Never called automatically.\n */\nexport async function sendFollowUp(\n api: MeetApi,\n meetingId: MeetingId,\n input: {\n readonly subject: string;\n readonly body: string;\n readonly recipientKeys: readonly string[];\n readonly dryRun?: boolean;\n },\n): Promise<FollowUpSendResult> {\n const operation = \"meet.sendFollowUp\";\n const response = await api.request({\n path: meetingPath(MEET_ROUTES.meetingFollowUp, meetingId),\n method: \"POST\",\n requireAuth: true,\n operation,\n body: {\n subject: input.subject,\n body: input.body,\n recipient_keys: [...input.recipientKeys],\n dry_run: input.dryRun === true,\n },\n });\n if (!response.ok) throw await refusalOf(response, operation);\n const body = (await response.json()) as Record<string, unknown>;\n return {\n dryRun: body[\"dry_run\"] === true,\n queued: Array.isArray(body[\"queued\"]) ? (body[\"queued\"] as string[]) : [],\n skipped: Array.isArray(body[\"skipped\"])\n ? (body[\"skipped\"] as Record<string, unknown>[]).map((row) => ({\n key: String(row[\"key\"] ?? \"\"),\n reason: String(row[\"reason\"] ?? \"\"),\n }))\n : [],\n };\n}\n","/**\n * MEET WAVE 1 — the two server calls a management screen makes (0.8).\n *\n * Every WRITE (schedule, edit, reschedule, cancel, archive, occurrence change,\n * invite, answer) goes straight to the database through `MeetRepository` — the\n * database decides who may. What a browser cannot do is send an email with a\n * calendar object in it, so after any of those writes a screen calls\n * `announceMeeting`: the server tells each invitee exactly what they have not\n * been told (invitation, update or cancellation, each with its `.ics`), and\n * re-queues reminders. It is idempotent — call it after every save.\n */\n\nimport type { MeetApi } from \"./api\";\nimport { readServerRefusal } from \"./ai\";\nimport { MeetError } from \"./errors\";\nimport { MEET_ROUTES, meetingPath } from \"./tokens\";\nimport type { MeetingId } from \"./types\";\n\nexport interface AnnounceResult {\n readonly invitations: number;\n readonly updates: number;\n readonly cancellations: number;\n readonly alreadyCurrent: number;\n readonly remindersQueued: number;\n readonly remindersCancelled: number;\n}\n\nasync function refusal(response: Response, operation: string): Promise<MeetError> {\n let body: unknown = null;\n try {\n body = await response.json();\n } catch {\n body = null;\n }\n const said = readServerRefusal(body);\n return new MeetError(\n response.status === 403 || response.status === 401\n ? \"forbidden\"\n : response.status === 404\n ? \"not-found\"\n : response.status === 409\n ? \"conflict\"\n : \"transport\",\n `${operation}: ${said?.reason ?? `the server answered ${response.status}`}`,\n said?.remedy ||\n \"The meeting itself is saved — only the telling failed. Try again; the call is idempotent.\",\n );\n}\n\nfunction count(body: Record<string, unknown>, key: string): number {\n const value = body[key];\n return typeof value === \"number\" ? value : 0;\n}\n\n/** Bring every invitee's inbox and calendar up to date. The host, a co-host or an editor. */\nexport async function announceMeeting(api: MeetApi, meetingId: MeetingId): Promise<AnnounceResult> {\n const operation = \"meet.announceMeeting\";\n const response = await api.request({\n path: meetingPath(MEET_ROUTES.meetingAnnounce, meetingId),\n method: \"POST\",\n requireAuth: true,\n operation,\n });\n if (!response.ok) throw await refusal(response, operation);\n const body = (await response.json()) as Record<string, unknown>;\n return {\n invitations: count(body, \"invitations\"),\n updates: count(body, \"updates\"),\n cancellations: count(body, \"cancellations\"),\n alreadyCurrent: count(body, \"already_current\"),\n remindersQueued: count(body, \"reminders_queued\"),\n remindersCancelled: count(body, \"reminders_cancelled\"),\n };\n}\n\n/**\n * Put a one-off meeting on the caller's own connected Google Calendar. GATED by\n * the server to Google's review accounts while the Calendar scope is in review —\n * a refusal is a `forbidden` MeetError carrying the server's sentence. Everyone\n * already gets the meeting into any calendar through the invitation's `.ics`.\n */\nexport async function pushMeetingToGoogleCalendar(\n api: MeetApi,\n meetingId: MeetingId,\n target: { connectionId: string; calendarId?: string },\n): Promise<Record<string, unknown>> {\n const operation = \"meet.pushMeetingToGoogleCalendar\";\n const response = await api.request({\n path: meetingPath(MEET_ROUTES.meetingGoogleCalendar, meetingId),\n method: \"POST\",\n requireAuth: true,\n operation,\n body: { connection_id: target.connectionId, calendar_id: target.calendarId ?? \"primary\" },\n });\n if (!response.ok) throw await refusal(response, operation);\n return (await response.json()) as Record<string, unknown>;\n}\n"],"mappings":"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","names":["row","refusal","text","ms","pending","current","deviceId","text","existing","refusal","options","text","refusal","text","deviceId","refusal","text","text","deviceId","useCallback","useEffect","useMemo","useRef","useState","count","when","refusal","useCallback","text","useState","useMemo","useEffect","useRef","useEffect","useMemo","useRef","useState","formatDurationMs","count","jsx","jsx","jsxs","useState","useEffect","useRef","text","deviceId","formatDurationMs","when","useMemo","notice","formatDurationMs","text","formatDurationMs"]}
|
|
1
|
+
{"version":3,"sources":["../src/react/provider.tsx","../src/core/ai.ts","../src/core/errors.ts","../src/core/tokens.ts","../src/core/api.ts","../src/core/channels.ts","../src/core/slot.ts","../src/core/types.ts","../src/core/calls.ts","../src/core/devices.ts","../src/core/names.ts","../src/core/recording.ts","../src/core/attendance.ts","../src/core/transcript.ts","../src/core/store.ts","../src/core/meetings.ts","../src/core/repository.ts","../src/core/session-identity.ts","../src/core/room-events.ts","../src/core/note-taker.ts","../src/core/room-driver.ts","../src/core/room.ts","../src/core/effects.ts","../src/core/in-room.ts","../src/core/livekit-driver.ts","../src/react/hooks.ts","../src/core/layout.ts","../src/core/record.ts","../src/react/components.tsx","../src/core/after.ts","../src/core/format.ts","../src/react/icons.tsx","../src/core/invitations.ts","../src/core/management.ts"],"sourcesContent":["\"use client\";\n\n/**\n * `<MeetProvider>` — the one place an app wires calls and meetings (R7).\n *\n * THE ONE-HOUR INTEGRATION CONTRACT is this component's job: a host passes a\n * Supabase client, who they are, their org, and aidream's base URL. Everything\n * else — the repository, the realtime manager and its three channels, the token\n * client, the room engine, the call center, the meeting session, the recording\n * controller, the device manager, the AI surface — is constructed and owned\n * here.\n *\n * What a host may inject is IDENTITY and app chrome: session source, a\n * navigator, a notification sink. It may NOT inject an agent id — as of 0.3.0\n * there is no prop for one, because which agent answers is a Mandate binding\n * the SERVER resolves (D2). What a host must NEVER have to inject is\n * behavior — if you find yourself catching a package error, retrying a package\n * call, or branching on a package quirk in host code, that logic belongs in\n * here (C22).\n *\n * 🚨 THE PROVIDER'S LIFETIME IS `client` + the SESSION'S user (or `guestName`)\n * + `organizationId` + `baseUrl`, AND NOTHING ELSE. Hosts pass fresh function\n * literals for `onDiagnostic` and `accessToken` on every render; keying the\n * runtime on those identities would tear down and rebuild every channel — and\n * drop the call in progress — on every parent re-render.\n *\n * 🚨 THERE IS NO `userId` PROP, AND THERE NEVER WILL BE AGAIN (DD-240, 0.6.0).\n * The acting user is read from `client`'s own session — the same client that\n * mints the JWT on every request — so the id in a `p_user_id` argument and the\n * id in the token cannot disagree. Through 0.5.x this was a prop, every host\n * filled it from a copy in its own state, and a rotated auth cookie left that\n * copy naming an account the tab could no longer prove it was:\n * `meet_pending_call_invites` refused it at 403 with \"the acting user … is not\n * the authenticated user\", 8.8 h and 32.9 h into two tabs' lives. The whole\n * story is in `../core/session-identity.ts`.\n *\n * 🚨 A GUEST IS A FIRST-CLASS IDENTITY (D6), not a degraded user. Pass\n * `guestName` and the provider builds a runtime with no calling surface and no\n * host powers, which is exactly what a link-follower needs — and, because a\n * guest has no account at all, the guest lane never reads the session. Nothing\n * downstream branches on \"is this a real user\".\n */\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from \"react\";\nimport {\n RealtimeProvider,\n useIsRealtimeProviderMounted,\n useRealtimeManager,\n} from \"@ai-matrx/realtime/react\";\nimport type { MessagingSupabaseClient } from \"@ai-matrx/messaging\";\nimport { createMeetAi, type MeetAi } from \"../core/ai\";\nimport { createMeetApi, type MeetApi } from \"../core/api\";\nimport { createCallCenter, type CallCenter } from \"../core/calls\";\nimport {\n createDeviceManager,\n createWebDeviceStorage,\n type DeviceManager,\n type DeviceSnapshot,\n type MediaDevicesLike,\n} from \"../core/devices\";\nimport { createMeetingSession, type MeetingSession } from \"../core/meetings\";\nimport { createRecordingController, type RecordingController } from \"../core/recording\";\nimport { createMeetRepository, type MeetRepository } from \"../core/repository\";\nimport {\n createSessionIdentity,\n SERVER_SESSION_IDENTITY,\n type SessionIdentitySnapshot,\n} from \"../core/session-identity\";\nimport { createRoomEngine, type RoomEngine } from \"../core/room\";\nimport { createWebEffectsStorage } from \"../core/effects\";\nimport { createInRoomClient, type InRoomClient } from \"../core/in-room\";\nimport { createLiveKitDriver } from \"../core/livekit-driver\";\nimport type { RoomDriverFactory } from \"../core/room-driver\";\nimport {\n createMeetStore,\n effectiveRole,\n type MeetSnapshot,\n type MeetStore,\n} from \"../core/store\";\nimport {\n createTokenClient,\n createWebRoomTokenStorage,\n type AccessTokenSource,\n type TokenClient,\n} from \"../core/tokens\";\nimport {\n asOrganizationId,\n isHostRole,\n type CallInvite,\n type MeetIdentity,\n type ParticipantRole,\n type UserId,\n} from \"../core/types\";\n\nexport interface MeetDiagnostic {\n readonly level: \"info\" | \"warn\" | \"error\";\n readonly message: string;\n readonly remedy?: string | undefined;\n}\n\nexport interface MeetHost {\n readonly store: MeetStore;\n readonly engine: RoomEngine;\n readonly calls: CallCenter | null;\n readonly meetings: MeetingSession;\n /**\n * Meet wave 2: host moderation and the SAVED chat, both decided and written by\n * the server (`core/in-room.ts`). A guest's calls carry their room pass.\n */\n readonly inRoom: InRoomClient;\n readonly recording: RecordingController;\n readonly devices: DeviceManager;\n readonly repository: MeetRepository;\n readonly tokens: TokenClient;\n /**\n * 🚨 NEVER NULL as of 0.3.0. Through 0.2.1 this was `null` unless the host\n * injected a transport AND four agent ids, so the meeting assistant silently\n * did not exist for any app that had not filled in a config line. The\n * capability is the SERVER's now: if a Mandate has no Holder bound, the\n * server refuses with a sentence naming the Mandate admin, and that sentence\n * is what the panel shows. Absence is a fact the server states, never a prop\n * a host forgot.\n */\n readonly ai: MeetAi;\n /**\n * 🚨 THE ONE WAY ANYTHING IN THIS PACKAGE TALKS TO AIDREAM (MRI-A16). Every\n * request it builds carries `x-organization-id`; a request built any other\n * way is refused by the org-admission middleware with 400\n * `organization_required`, and `core/api.test.ts` fails the build if a second\n * way appears. Playing a recording — `GET /files/{id}/download` — goes\n * through here too, which is the defect this replaced.\n */\n readonly api: MeetApi;\n readonly identity: MeetIdentity;\n readonly baseUrl: string;\n /**\n * The host's session source, as handed to `<MeetProvider>`. Exposed for the\n * host's own diagnostics; package code reaches aidream through `api`.\n */\n readonly accessToken: AccessTokenSource;\n readonly report: (event: MeetDiagnostic) => void;\n}\n\nconst MeetContext = createContext<MeetHost | null>(null);\n\nexport interface MeetProviderProps {\n /**\n * Any Supabase client. `null` while the host is still resolving one.\n *\n * 🚨 DELIBERATELY THE SHALLOW SHAPE (0.2.1) — pass the\n * `SupabaseClient<Database>` you already have, with no cast. The rich\n * internal contract sent tsc into `TS2589` for any host with generated\n * Supabase types; see `core/repository.ts`'s header for the whole story.\n */\n client: MessagingSupabaseClient | null | undefined;\n /** aidream's base URL. LiveKit credentials live THERE, never here. */\n baseUrl: string;\n /**\n * A guest's typed name — and the ONE way to declare the guest lane (D6).\n * With it, this mount is a link-follower's room: no session is read, no\n * calling surface is built, and nothing user-scoped is ever issued. Without\n * it, the acting user is whoever `client`'s session says it is.\n *\n * 🚨 There is NO `userId` prop. See this file's header and\n * `../core/session-identity.ts`.\n */\n guestName?: string | null | undefined;\n organizationId: string | null | undefined;\n displayName?: string | undefined;\n avatarUrl?: string | null | undefined;\n /** The bearer token source for aidream calls. */\n accessToken: AccessTokenSource;\n /** Swap the media driver. Defaults to LiveKit — there is no reason to. */\n driverFactory?: RoomDriverFactory | undefined;\n /** A call is ringing this device — for a sound, a toast, or a badge. */\n onIncomingCall?: ((invite: CallInvite) => void) | undefined;\n onDiagnostic?: ((event: MeetDiagnostic) => void) | undefined;\n ringTimeoutMs?: number | undefined;\n children: ReactNode;\n}\n\nfunction defaultDiagnostics(event: MeetDiagnostic): void {\n const line = `[@ai-matrx/meet] ${event.message}${\n event.remedy !== undefined ? `\\n → ${event.remedy}` : \"\"\n }`;\n if (event.level === \"error\") console.error(line);\n else if (event.level === \"warn\") console.warn(line);\n else console.info(line);\n}\n\n/** A stable per-device id, so a reconnect keeps ONE LiveKit identity. */\nfunction deviceId(): string {\n const storage = (globalThis as { localStorage?: Storage }).localStorage;\n const key = \"mx.meet.device\";\n try {\n const existing = storage?.getItem(key);\n if (existing !== null && existing !== undefined && existing.length > 0) return existing;\n const created = Math.random().toString(36).slice(2, 14);\n storage?.setItem(key, created);\n return created;\n } catch {\n return Math.random().toString(36).slice(2, 14);\n }\n}\n\n/**\n * THE ONE SESSION READ. Subscribed per client, torn down with it, and honest\n * about the `resolving` window in between — see `../core/session-identity.ts`\n * for the class this closes.\n *\n * `client === null` (the guest lane, or a host still resolving one) never opens\n * a subscription at all: a link-follower has no account to read.\n */\nfunction useSessionIdentity(\n client: MessagingSupabaseClient | null | undefined,\n report: (event: MeetDiagnostic) => void,\n): SessionIdentitySnapshot {\n const [snapshot, setSnapshot] = useState<SessionIdentitySnapshot>(SERVER_SESSION_IDENTITY);\n\n useEffect(() => {\n if (client == null) {\n setSnapshot(SERVER_SESSION_IDENTITY);\n return undefined;\n }\n const identity = createSessionIdentity({ client, onDiagnostic: report });\n setSnapshot(identity.snapshot());\n const unsubscribe = identity.subscribe(() => setSnapshot(identity.snapshot()));\n return () => {\n unsubscribe();\n identity.dispose();\n };\n }, [client, report]);\n\n return snapshot;\n}\n\n/** A guest lane is declared by a NON-EMPTY typed name, and by nothing else. */\nfunction guestLaneName(guestName: string | null | undefined): string | null {\n return typeof guestName === \"string\" && guestName.trim().length > 0 ? guestName : null;\n}\n\nexport function MeetProvider(props: MeetProviderProps): ReactNode {\n const { client } = props;\n\n // Live ref so a host's fresh function literal per render never becomes part\n // of anything's lifetime, while callbacks still see the CURRENT one.\n const diagnosticRef = useRef(props.onDiagnostic);\n diagnosticRef.current = props.onDiagnostic;\n const report = useCallback((event: MeetDiagnostic): void => {\n (diagnosticRef.current ?? defaultDiagnostics)(event);\n }, []);\n\n // 🚨 NOTHING FAILS SILENTLY. A host still passing the 0.5.x `userId` prop —\n // a stale bundle, a JS consumer tsc never checked — is told, once, that it is\n // ignored and why. Silently dropping it would look exactly like the bug.\n const legacyUserIdReported = useRef(false);\n const legacyUserId = (props as { userId?: unknown }).userId;\n useEffect(() => {\n if (legacyUserId === undefined || legacyUserId === null) return;\n if (legacyUserIdReported.current) return;\n legacyUserIdReported.current = true;\n report({\n level: \"error\",\n message:\n \"<MeetProvider userId> is ignored: since 0.6.0 Meet reads the acting user from the \" +\n \"Supabase client's own session.\",\n remedy:\n \"Delete the userId prop. Passing a copy of the user id is what let a tab whose auth \" +\n \"cookie had rotated issue reads as an account it could no longer prove it was — the \" +\n \"database refused them at 403 (DD-240).\",\n });\n }, [legacyUserId, report]);\n\n const guestName = guestLaneName(props.guestName);\n // The guest lane reads no session; the member lane reads nothing else.\n const session = useSessionIdentity(guestName === null ? client : null, report);\n const actingUserId = guestName === null ? session.userId : null;\n\n // 🚨 RIDE THE HOST'S REALTIME MANAGER WHEN THERE IS ONE (0.6.5).\n //\n // Through 0.6.4 this ALWAYS mounted a provider of its own, with `client={null}`\n // until an organization was selected. That shadowed the host's manager for\n // everything below Meet: a sibling that rides a mounted host provider (as\n // `@ai-matrx/messaging` does) read a NULL manager forever when no org was\n // selected — `/messages` spun and a thread showed \"0 members\" — and with an\n // org selected it got a SECOND manager (two sockets, two write ledgers).\n // The probe is provider PRESENCE (`@ai-matrx/realtime` 0.3.0), never\n // `useRealtimeManager() !== null`, which is also null while a mounted host\n // provider waits for its client.\n //\n // And the realtime connection never waits on the organization: a socket is\n // the PERSON's (access belongs to the person, 2026-09-23). Whether Meet's own\n // runtime needs an org is MeetRuntime's question, not the transport's.\n const hostProvidesRealtime = useIsRealtimeProviderMounted();\n const runtime = (\n <MeetRuntime\n {...props}\n report={report}\n actingUserId={actingUserId}\n guestLaneName={guestName}\n sessionResolved={guestName !== null || session.state === \"resolved\"}\n />\n );\n if (hostProvidesRealtime) return runtime;\n return (\n <RealtimeProvider\n client={client != null ? (client as never) : null}\n actorId={actingUserId ?? undefined}\n >\n {runtime}\n </RealtimeProvider>\n );\n}\n\ninterface MeetRuntimeProps extends MeetProviderProps {\n readonly report: (event: MeetDiagnostic) => void;\n /** Who the SESSION says is acting. Never a prop from outside the package. */\n readonly actingUserId: UserId | null;\n readonly guestLaneName: string | null;\n readonly sessionResolved: boolean;\n}\n\nfunction MeetRuntime(props: MeetRuntimeProps): ReactNode {\n const { client, actingUserId, guestLaneName: guestName, organizationId, baseUrl, children } =\n props;\n const report = props.report;\n const manager = useRealtimeManager();\n\n // Live refs so callbacks always see the CURRENT render's functions without\n // those functions' identities being part of the runtime's lifetime.\n const incomingRef = useRef(props.onIncomingCall);\n incomingRef.current = props.onIncomingCall;\n const accessTokenRef = useRef(props.accessToken);\n accessTokenRef.current = props.accessToken;\n const driverRef = useRef(props.driverFactory);\n driverRef.current = props.driverFactory;\n\n const displayName =\n props.displayName ?? (typeof guestName === \"string\" ? guestName : \"Guest\");\n\n // 🚨 INERT UNTIL THE SESSION HAS ANSWERED. A runtime built during the\n // `resolving` window would issue its first `pendingInvites` read on behalf of\n // a guess; the whole point of DD-240 is that there is no guess.\n const ready =\n client != null &&\n manager !== null &&\n typeof organizationId === \"string\" &&\n organizationId.length > 0 &&\n props.sessionResolved &&\n (guestName !== null || actingUserId !== null);\n\n const host = useMemo<MeetHost | null>(() => {\n if (!ready || manager === null || client == null) return null;\n\n const identity: MeetIdentity = {\n // THE SESSION'S ANSWER, never a prop (DD-240).\n userId: actingUserId,\n organizationId: asOrganizationId(organizationId as string),\n displayName,\n avatarUrl: props.avatarUrl ?? null,\n deviceId: deviceId(),\n };\n\n const effectsStorage = createWebEffectsStorage();\n // Seeded BEFORE the room: the pre-join screen shows (and previews) the\n // remembered choice, and the engine applies the same one on connect.\n const store = createMeetStore({ effects: effectsStorage.load() });\n const devicesHolder: { current: DeviceManager | null } = { current: null };\n const api = createMeetApi({\n baseUrl,\n organizationId: identity.organizationId,\n accessToken: (...args) => accessTokenRef.current(...args),\n });\n const repository = createMeetRepository({ client });\n // MRF-1: a GUEST's pass is kept on this device so the durable link still\n // opens the record after the meeting — `/token` will not mint another one\n // for a finished meeting, correctly, and a guest has no session to prove\n // they were here with. `createTokenClient` stores only guest passes.\n const tokens = createTokenClient({\n api,\n storage: createWebRoomTokenStorage((message, remedy) =>\n report({ level: \"warn\", message, remedy }),\n ),\n });\n const engine = createRoomEngine({\n store,\n tokens,\n identity,\n resolveMeeting: (slug) => repository.meetingBySlug(slug),\n driverFactory: (handlers) =>\n (driverRef.current ?? createLiveKitDriver)(handlers),\n onDiagnostic: report,\n effectsStorage,\n resolveDevice: (kind) => devicesHolder.current?.resolve(kind) ?? null,\n });\n const meetings = createMeetingSession({\n manager,\n repository,\n store,\n identity,\n api,\n onDiagnostic: report,\n // ADMISSION IS A JOIN, NOT A RE-RENDER. The lobby token grants neither\n // publish nor subscribe, so the host saying yes has to mint a new one.\n onAdmitted: () => {\n void engine.rejoin();\n },\n // A \"no\" is ALSO a mint: the server refuses it with its own sentence, which\n // turns the waiting room into the pre-join screen showing that sentence.\n onDenied: () => {\n void engine.rejoin().catch(() => undefined);\n },\n });\n // THE AI IS PART OF THE RUNTIME, not an optional attachment. Nothing here\n // names an agent: every capability is a server-owned Mandate (D2).\n const resolveRoomToken = (): string | null => {\n const roomName = store.snapshot().meeting?.roomName;\n if (roomName === undefined) return null;\n const active = engine.token();\n if (active?.roomName === roomName && active.token.length > 0) return active.token;\n return tokens.remembered(roomName)?.token ?? null;\n };\n const ai = createMeetAi({ api, store, resolveRoomToken });\n const inRoom = createInRoomClient({ api, store, resolveRoomToken });\n // THE SAVED CHAT IS READ ON EVERY JOIN (Meet wave 2) — that is what makes a\n // late joiner see what was already said. Once per connected room; a refusal\n // is a diagnostic with a remedy, and live messages keep arriving regardless.\n let chatReadFor: string | null = null;\n store.subscribe(() => {\n const snapshot = store.snapshot();\n if (snapshot.phase !== \"connected\" || snapshot.meeting === null) {\n if (snapshot.phase === \"left\" || snapshot.phase === \"idle\") chatReadFor = null;\n return;\n }\n if (chatReadFor === snapshot.meeting.id) return;\n chatReadFor = snapshot.meeting.id;\n void inRoom.loadChat().catch((error: unknown) => {\n const normalized = error as { message?: string; remedy?: string };\n // NEVER \"Reading…\" FOREVER: the panel says history is unavailable, and why.\n store.patch({\n chatLoaded: true,\n chatHistoryError:\n normalized.remedy ?? \"Messages sent before you joined could not be read. New messages still arrive.\",\n });\n report({\n level: \"warn\",\n message: normalized.message ?? \"meet: the saved chat could not be read\",\n ...(normalized.remedy !== undefined ? { remedy: normalized.remedy } : {}),\n });\n });\n });\n const recording = createRecordingController({\n api,\n store,\n acknowledgeConsent: async (meetingId) => {\n await repository.recordConsent({\n meetingId,\n identity: store.snapshot().localIdentity ?? identity.deviceId,\n acknowledgedAt: new Date().toISOString(),\n });\n },\n });\n const devices = createDeviceManager({\n media: (globalThis as unknown as { navigator?: { mediaDevices?: MediaDevicesLike } })\n .navigator?.mediaDevices ?? {\n // An SSR render or a browser without media devices gets an INERT\n // manager that reports the truth, rather than a crash on import.\n enumerateDevices: async () => [],\n getUserMedia: async () => ({ getTracks: () => [] }),\n },\n storage: createWebDeviceStorage(),\n });\n devicesHolder.current = devices;\n // A GUEST HAS NO CALLING SURFACE. Not \"a disabled one\" — none at all, so\n // there is nothing to render as a dead button (D6, no dead ends).\n const calls =\n identity.userId === null\n ? null\n : createCallCenter({\n manager,\n repository,\n store,\n identity,\n onIncoming: (invite) => incomingRef.current?.(invite),\n onDiagnostic: report,\n ...(props.ringTimeoutMs !== undefined ? { ringTimeoutMs: props.ringTimeoutMs } : {}),\n });\n\n return {\n store,\n engine,\n calls,\n meetings,\n inRoom,\n recording,\n devices,\n repository,\n tokens,\n ai,\n api,\n identity,\n baseUrl,\n accessToken: (...args) => accessTokenRef.current(...args),\n report,\n };\n // 🚨 IDENTITY ONLY. See the header: adding callbacks or option objects here\n // rebuilds every channel — and drops the call in progress — on every render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n ready,\n manager,\n client,\n actingUserId,\n guestName,\n organizationId,\n baseUrl,\n displayName,\n report,\n ]);\n\n useEffect(() => {\n if (host?.calls == null) return undefined;\n const center = host.calls;\n void center.start().catch((error: unknown) => {\n host.report({\n level: \"error\",\n message: `Meet could not start listening for calls: ${String(\n (error as Error)?.message ?? error,\n )}`,\n remedy:\n \"Calls will not ring on this device until this succeeds. Check the session and \" +\n \"organization, then reload the surface.\",\n });\n });\n return () => {\n center.dispose();\n };\n }, [host]);\n\n useEffect(() => {\n if (host === null) return undefined;\n return () => {\n host.meetings.dispose();\n host.devices.dispose();\n void host.engine.dispose();\n };\n }, [host]);\n\n return <MeetContext.Provider value={host}>{children}</MeetContext.Provider>;\n}\n\n/** The host, or `null` while auth/org are still resolving. */\nexport function useMeetHost(): MeetHost | null {\n return useContext(MeetContext);\n}\n\nexport function useRequiredMeetHost(): MeetHost {\n const host = useMeetHost();\n if (host === null) {\n throw new Error(\n \"[@ai-matrx/meet] No meet host. Wrap this tree in <MeetProvider client={supabase} \" +\n \"baseUrl={aidreamUrl} organizationId={orgId} accessToken={fn}> and render it only \" +\n \"once auth has resolved.\",\n );\n }\n return host;\n}\n\n/** The whole room snapshot, re-rendering only when it actually changes. */\nexport function useMeetSnapshot(): MeetSnapshot | null {\n const host = useMeetHost();\n const store = host?.store ?? null;\n const empty = useRef<MeetSnapshot | null>(null);\n return useSyncExternalStore(\n (listener) => (store === null ? () => undefined : store.subscribe(listener)),\n () => (store === null ? empty.current : store.snapshot()),\n () => (store === null ? empty.current : store.snapshot()),\n );\n}\n\nexport function useDeviceSnapshot(): DeviceSnapshot | null {\n const host = useMeetHost();\n const devices = host?.devices ?? null;\n return useSyncExternalStore(\n (listener) => (devices === null ? () => undefined : devices.subscribe(() => listener())),\n () => devices?.snapshot() ?? null,\n () => devices?.snapshot() ?? null,\n );\n}\n\n/**\n * 🚨 THE LOCAL PARTICIPANT'S ROLE — THE SERVER'S WORD, FROM BOTH ITS CARRIERS\n * (MRI-A11, feedback `7418ef78`).\n *\n * Two sources, one decision made once in `services/meet/service.py`:\n *\n * 1. `snapshot.grants.role` — the `/meet/token` response, in the store from the\n * instant the token lands, which is BEFORE any LiveKit roster exists.\n * 2. the local participant's roster entry, whose role comes from the\n * `matrx.participant.role` LiveKit attribute the same mint published.\n *\n * The stronger of the two wins, and both are server-minted, so this can never\n * be client state: there is no branch here a browser could take on its own.\n * Reading only (2) is the shipped defect this replaces — a roster entry arrives\n * a beat later than the token and, before MRI-A11, carried no role at all.\n */\nexport function useRole(): ParticipantRole {\n const snapshot = useMeetSnapshot();\n // ONE definition, shared with the code that PERFORMS the host actions\n // (`core/store.ts`). A second copy here is how the UI and the action drift.\n return snapshot === null ? \"participant\" : effectiveRole(snapshot);\n}\n\n/** Does the local participant hold host powers? ONE predicate, one definition. */\nexport function useIsHost(): boolean {\n return isHostRole(useRole());\n}\n\n/**\n * May the local participant start a recording? NOT `isHost` — the meeting's\n * recording policy is the server's, and an `always-on` meeting is recorded by\n * the server with no host control at all (MRI-A11).\n */\nexport function useCanRecord(): boolean {\n const snapshot = useMeetSnapshot();\n if (snapshot === null) return false;\n const me = snapshot.participants.find(\n (participant) => participant.identity === snapshot.localIdentity,\n );\n return snapshot.grants.canRecord || me?.canRecord === true;\n}\n\nexport function useLocalUserId(): UserId | null {\n return useMeetHost()?.identity.userId ?? null;\n}\n","/**\n * AI-NATIVE, ON BY DEFAULT — and SERVER-OWNED as of 0.3.0 (R4, D2, D16).\n *\n * 🚨 **THE PACKAGE NO LONGER KNOWS WHO ANSWERS.** Through 0.2.1 a host injected\n * `MeetAgents` — four database row ids — and this module ran the agent itself,\n * shipping the transcript up as `variables`. Both halves of that are gone:\n *\n * 1. **No agent id crosses this boundary, and none is injected.** Reasoning runs\n * behind Mandates whose Holder is resolved from the database at run time\n * (`meet.live_notes`, `meet.live_intelligence`, `meet.wrap_up`), so an\n * organization rebinds the job in the Mandate admin with no release of this\n * package and no change in the host. A host that had to supply an id was a\n * host that could supply the WRONG id, and a capability that silently\n * disappeared when nobody had filled a config line.\n * 2. **No transcript crosses this boundary either.** `POST /v1/meet/intelligence/ask`\n * takes `{meeting_id, question}` and NOTHING else; the answer is built\n * server-side from durable rows. Captions are hints and this client holds\n * only hints (D16) — sending them would be sending the model our guesses.\n *\n * What is left here is small and honest: ask a question and render the answer\n * as it streams, summon or dismiss the note-taker, end the meeting for\n * everyone, and report the server's refusal in the server's own words.\n *\n * 🚨 **THE USER-INPUT LAW still holds** and is now the server's to keep:\n * `question` is the one genuine human utterance in this module, and it is the\n * only free text this package sends anywhere near a model.\n */\n\nimport { readMatrxNdjsonStream } from \"@ai-matrx/agents\";\nimport type { MeetApi } from \"./api\";\nimport { MeetError } from \"./errors\";\nimport type { NoteTakerRefusal } from \"./note-taker\";\nimport type { MeetStore } from \"./store\";\nimport { MEET_ROUTES, ROOM_TOKEN_HEADER } from \"./tokens\";\nimport type { MeetingId, RoomName } from \"./types\";\n\nexport interface MeetAiOptions {\n /** The ONE org-aware aidream client (MRI-A16). Owns base url and headers. */\n api: MeetApi;\n store: MeetStore;\n /**\n * Resolves the current meeting's room pass for a guest Q&A request. The\n * provider owns this because it alone has both the active room and its\n * persisted guest pass. `null` leaves the header absent for signed-in record\n * Q&A, where the session remains the credential.\n */\n resolveRoomToken?: (() => string | null) | undefined;\n}\n\n/** What the answer was built from. The server measures it; we never guess it. */\nexport interface MeetAnswerCoverage {\n readonly segmentsUsed: number;\n readonly segmentsTotal: number;\n readonly truncated: boolean;\n readonly speakers: readonly string[];\n}\n\nexport interface MeetAiAnswer {\n readonly text: string;\n readonly coverage: MeetAnswerCoverage | null;\n}\n\nexport interface AskArgs {\n readonly meetingId: MeetingId;\n readonly question: string;\n readonly signal?: AbortSignal | undefined;\n /** Called with the answer so far, every time it grows. Rendering is live. */\n readonly onText?: ((text: string) => void) | undefined;\n /** The server's phase, verbatim, so a slow answer is never a bare spinner. */\n readonly onPhase?: ((phase: string) => void) | undefined;\n}\n\nexport interface NoteTakerDispatch {\n readonly dispatched: boolean;\n /** The server's sentence. Never empty on a refusal. */\n readonly detail: string;\n}\n\nexport interface MeetAi {\n /** In-meeting Q&A. The ONE human utterance this package sends (D16). */\n ask(args: AskArgs): Promise<MeetAiAnswer>;\n /** Ask aidream to dispatch the note-taker INTO the room. Host-only. */\n startNoteTaker(args: { meetingId: MeetingId; roomName: RoomName }): Promise<NoteTakerDispatch>;\n /** Dismiss it. Nothing automatic brings a dismissed note-taker back (D9). */\n stopNoteTaker(args: { meetingId: MeetingId }): Promise<NoteTakerDispatch>;\n}\n\n/** The event vocabulary `/intelligence/ask` emits, pinned by the server's FEATURE.md. */\nexport const MEET_ANSWER_EVENTS = {\n chunk: \"chunk\",\n info: \"info\",\n phase: \"phase\",\n error: \"error\",\n end: \"end\",\n} as const;\n\n/** The `info` event carrying what the answer was built from. */\nexport const MEET_ANSWER_CONTEXT_EVENT = \"meet_intelligence_context\";\n\n/**\n * The coverage numbers, wherever the canonical emitter put them.\n *\n * 🚨 THE LIVE WIRE NESTS THEM UNDER `metadata`. `InfoPayload` is\n * `{code, system_message, user_message, metadata}`, so the numbers arrive at\n * `data.metadata.segments_used` — not at `data.segments_used`, which is what\n * this function read until it was walked against the real route on 2026-09-08\n * and quietly reported no coverage at all. Every shape is read now, and the\n * fixture in `ai.test.ts` is a VERBATIM line off the production stream.\n */\nfunction readCoverage(data: unknown): MeetAnswerCoverage | null {\n if (typeof data !== \"object\" || data === null) return null;\n const row = data as Record<string, unknown>;\n const candidates: Record<string, unknown>[] = [row];\n for (const key of [\"metadata\", \"data\"]) {\n const nested = row[key];\n if (typeof nested === \"object\" && nested !== null && !Array.isArray(nested)) {\n candidates.push(nested as Record<string, unknown>);\n }\n }\n const source =\n candidates.find(\n (entry) =>\n typeof entry[\"segments_used\"] === \"number\" ||\n typeof entry[\"segments_total\"] === \"number\",\n ) ?? null;\n if (source === null) return null;\n const used = source[\"segments_used\"];\n const total = source[\"segments_total\"];\n const speakers = source[\"speakers\"];\n return {\n segmentsUsed: typeof used === \"number\" ? used : 0,\n segmentsTotal: typeof total === \"number\" ? total : 0,\n truncated: source[\"transcript_truncated\"] === true,\n speakers: Array.isArray(speakers)\n ? speakers.filter((entry): entry is string => typeof entry === \"string\")\n : [],\n };\n}\n\nfunction readText(data: unknown): string {\n if (typeof data === \"string\") return data;\n if (typeof data !== \"object\" || data === null) return \"\";\n const row = data as Record<string, unknown>;\n // `phase` and `system_message` are on this list because the live emitter\n // sends `{\"phase\":\"generating\"}` and `{\"system_message\":\"Reading the meeting\n // transcript\"}`. Without them a phase rendered as \"[object Object]\" —\n // found by walking the real route, not by any test written from the docs.\n for (const key of [\"text\", \"content\", \"delta\", \"t\", \"phase\", \"system_message\"]) {\n const value = row[key];\n if (typeof value === \"string\") return value;\n }\n return \"\";\n}\n\n/** What a person reads when the server failed without a sentence of its own. */\nexport const SERVER_FAILED_SENTENCE =\n \"The server hit an unexpected problem and nothing was changed.\";\n\n/**\n * A developer's text, not a person's: `Internal server error: SomeError`, a\n * bare `SomeError` class name, or a machine code like `internal_error`.\n */\nexport function isRawServerText(value: string): boolean {\n const text = value.trim();\n return (\n /^internal server error\\b/i.test(text) ||\n /^[A-Z][A-Za-z0-9]*(Error|Exception)$/.test(text) ||\n /^[a-z][a-z0-9]*(_[a-z0-9]+)+$/.test(text)\n );\n}\n\n/**\n * THE ONE REFUSAL → MeetError (0.7.8). A non-OK aidream response becomes an\n * error whose `message` is the server's sentence for a PERSON and whose\n * `remedy` is the server's remedy (or the caller's fallback) — never the\n * operation name, a status code alone, or an exception class. Every door that\n * calls aidream builds its refusal here, so no door can drift back.\n */\nexport async function refusalFromResponse(\n response: Response,\n operation: string,\n fallbackRemedy: string,\n): Promise<MeetError> {\n let body: unknown = null;\n try {\n body = await response.json();\n } catch {\n body = null;\n }\n const said = readServerRefusal(body);\n const code =\n response.status === 403 || response.status === 401\n ? \"forbidden\"\n : response.status === 404\n ? \"not-found\"\n : response.status === 409\n ? \"conflict\"\n : \"transport\";\n const error = new MeetError(\n code,\n said?.reason ?? SERVER_FAILED_SENTENCE,\n said !== null && said.remedy.length > 0 ? said.remedy : fallbackRemedy,\n );\n (error as { operation?: string; status?: number }).operation = operation;\n (error as { operation?: string; status?: number }).status = response.status;\n return error;\n}\n\ninterface ServerRefusal {\n readonly reason: string;\n readonly remedy: string;\n}\n\n/**\n * THE SERVER'S REFUSAL, READ RATHER THAN RE-WRITTEN.\n *\n * aidream answers a refused dispatch with a body carrying its own `reason` and\n * `remedy` — \"no worker is registered under matrx-note-taker\", and what to do\n * about it. FastAPI nests a raised `HTTPException` under `detail`, and a\n * validation failure produces a list. All three shapes are read here so the\n * screen shows the system's own words instead of \"something went wrong\".\n */\nexport function readServerRefusal(body: unknown): ServerRefusal | null {\n if (typeof body === \"string\") {\n return body.trim().length === 0 ? null : { reason: body.trim(), remedy: \"\" };\n }\n if (typeof body !== \"object\" || body === null) return null;\n const row = body as Record<string, unknown>;\n const detail = row[\"detail\"];\n if (Array.isArray(detail)) {\n // FastAPI's validation shape: `{msg, loc}`. The FIELD is in `loc` and the\n // field is the whole point — \"Field required\" alone names nothing.\n const messages = detail\n .map((entry) => {\n if (typeof entry !== \"object\" || entry === null) return String(entry);\n const row = entry as Record<string, unknown>;\n const message = String(row[\"msg\"] ?? \"\");\n const where = Array.isArray(row[\"loc\"])\n ? row[\"loc\"].filter((part): part is string => typeof part === \"string\").join(\".\")\n : \"\";\n return where.length > 0 ? `${message} (${where})` : message;\n })\n .filter((entry) => entry.length > 0);\n return messages.length === 0 ? null : { reason: messages.join(\"; \"), remedy: \"\" };\n }\n if (typeof detail === \"object\" && detail !== null) return readServerRefusal(detail);\n // 🚨 NEVER A CLASS NAME. aidream's crash body is `message: \"Internal server\n // error: UnsupportedClientFeatureError\"` beside `user_message` for a person;\n // through 0.7.7 this read `message` whatever it said, so a crash reached a\n // host's toast as a Python class name (verifier, 2026-09-27). A raw message\n // now falls through to `user_message`. A HUMAN `message` still wins: Meet's\n // own sentences carry the specific reason and its \"Fix:\", which a generic\n // `user_message` wrapper would bury.\n const humanOrNull = (value: unknown): string | null =>\n typeof value === \"string\" && value.trim().length > 0 && !isRawServerText(value)\n ? value.trim()\n : null;\n const reason =\n humanOrNull(row[\"reason\"]) ??\n humanOrNull(row[\"message\"]) ??\n humanOrNull(row[\"user_message\"]) ??\n (typeof detail === \"string\" ? humanOrNull(detail) : null) ??\n (typeof row[\"message\"] === \"string\" ||\n typeof row[\"error\"] === \"string\" ||\n typeof detail === \"string\"\n ? SERVER_FAILED_SENTENCE\n : null);\n if (reason === null) return null;\n const remedy = typeof row[\"remedy\"] === \"string\" ? row[\"remedy\"] : \"\";\n if (remedy.length > 0) return { reason, remedy };\n // THE SERVER WRITES ITS REMEDY INLINE. Meet's own errors read\n // \"<what happened>. Fix: <what to do>.\" — splitting it here is what puts the\n // fix on its own line in the panel instead of burying it mid-paragraph.\n const fix = reason.indexOf(\"Fix:\");\n if (fix > 0) {\n return {\n reason: reason.slice(0, fix).trim(),\n remedy: reason.slice(fix + \"Fix:\".length).trim(),\n };\n }\n return { reason, remedy };\n}\n\nexport function createMeetAi(options: MeetAiOptions): MeetAi {\n /**\n * Every request here goes through the ONE org-aware client (MRI-A16), which\n * puts `x-organization-id` on it — the 0.1.3 lesson, now structural rather\n * than remembered. A refused session is translated into THIS surface's own\n * sentence, because \"sign in\" means something specific for the note-taker.\n */\n async function send(input: {\n path: string;\n body: Record<string, unknown>;\n operation: string;\n requireAuth: boolean;\n headers?: Record<string, string> | undefined;\n signal?: AbortSignal | undefined;\n }): Promise<Response> {\n try {\n return await options.api.request({\n path: input.path,\n method: \"POST\",\n requireAuth: input.requireAuth,\n operation: input.operation,\n body: input.body,\n ...(input.headers !== undefined ? { headers: input.headers } : {}),\n ...(input.signal !== undefined ? { signal: input.signal } : {}),\n });\n } catch (error) {\n if ((error as { code?: string }).code === \"session-unavailable\") {\n throw new MeetError(\n \"forbidden\",\n `${input.operation}: this action needs a signed-in host`,\n \"A guest cannot summon or dismiss the note-taker, and the control is hidden for \" +\n \"them. Sign in as the meeting's host to use it.\",\n );\n }\n throw error;\n }\n }\n\n async function refusalFor(response: Response, operation: string): Promise<NoteTakerRefusal> {\n let body: unknown = null;\n try {\n body = await response.json();\n } catch {\n try {\n body = await response.text();\n } catch {\n body = null;\n }\n }\n const parsed = readServerRefusal(body);\n // 🚨 A NAMED SERVER GAP, ANNOUNCED RATHER THAN PAPERED OVER. 0.3.0 stopped\n // sending `agent_id` because which agent transcribes is the server's\n // business (D2), but aidream's `NoteTakerStartRequest` still DECLARES that\n // field, so a server that has not landed the MRI-A2 side answers FastAPI's\n // validation error — which reads like a client bug to the person clicking.\n // This translates it into what is actually true. It never invents an id.\n if (response.status === 422 && (parsed?.reason ?? \"\").includes(\"agent_id\")) {\n return {\n status: 422,\n reason:\n \"This server still expects the caller to name the note-taker agent, and this \" +\n \"version of @ai-matrx/meet deliberately does not.\",\n remedy:\n \"The note-taker's identity is a Mandate binding the server resolves (D2). Update \" +\n \"aidream so `/v1/meet/agent/start` resolves the agent itself — register item \" +\n \"MRI-A2/A6. Until then the note-taker cannot be summoned from this surface, and \" +\n \"nothing about this meeting is being transcribed.\",\n };\n }\n return {\n status: response.status,\n reason:\n parsed?.reason ??\n `${operation}: the server answered ${response.status} with no reason.`,\n remedy:\n parsed?.remedy !== undefined && parsed.remedy.length > 0\n ? parsed.remedy\n : \"The server refused and said nothing more. The meeting continues WITHOUT the \" +\n \"note-taker and this surface says so — a silent failure here is a meeting \" +\n \"everyone believes is being minuted.\",\n };\n }\n\n async function dispatch(\n route: string,\n body: Record<string, unknown>,\n operation: string,\n ): Promise<NoteTakerDispatch> {\n // The session check happens BEFORE the request, so a guest's refusal is a\n // package sentence rather than a round trip the server would reject anyway.\n const response = await send({ path: route, body, operation, requireAuth: true });\n if (!response.ok) {\n const refusal = await refusalFor(response, operation);\n // THE REFUSAL IS STATE, not only an exception: every surface renders the\n // server's sentence until the next attempt, rather than a control that\n // looks like it did nothing.\n options.store.patch({ noteTakerRefusal: refusal });\n throw new MeetError(\n response.status === 403 ? \"forbidden\" : \"transport\",\n refusal.reason,\n refusal.remedy,\n );\n }\n options.store.patch({ noteTakerRefusal: null });\n let payload: unknown = null;\n try {\n payload = await response.json();\n } catch {\n payload = null;\n }\n const row =\n typeof payload === \"object\" && payload !== null\n ? (payload as Record<string, unknown>)\n : {};\n return {\n dispatched: row[\"dispatched\"] === true,\n detail: typeof row[\"detail\"] === \"string\" ? row[\"detail\"] : \"\",\n };\n }\n\n return {\n async ask({ meetingId, question, signal, onText, onPhase }) {\n const trimmed = question.trim();\n if (trimmed.length === 0) {\n throw new MeetError(\n \"misconfigured\",\n \"meet.ai.ask: an empty question\",\n \"Type a question. Nothing is sent until there is one.\",\n );\n }\n const roomToken = options.resolveRoomToken?.() ?? null;\n const response = await send({\n path: MEET_ROUTES.intelligenceAsk,\n // THE WHOLE BODY. No transcript, no context, no agent id (D16).\n body: { meeting_id: meetingId, question: trimmed },\n operation: \"meet.ai.ask\",\n // A GUEST MAY ASK. The server decides whether it can answer.\n requireAuth: false,\n ...(roomToken !== null ? { headers: { [ROOM_TOKEN_HEADER]: roomToken } } : {}),\n ...(signal !== undefined ? { signal } : {}),\n });\n if (!response.ok) {\n // Both refusals happen BEFORE the stream opens, by the server's design,\n // so this is an honest status rather than a stream that dies mid-answer.\n const refusal = await refusalFor(response, \"meet.ai.ask\");\n throw new MeetError(\n response.status === 403 || response.status === 401\n ? \"forbidden\"\n : response.status === 404\n ? \"not-found\"\n : \"transport\",\n refusal.reason,\n refusal.remedy,\n );\n }\n const body = response.body;\n if (body === null || body === undefined) {\n throw new MeetError(\n \"invalid-response\",\n \"meet.ai.ask: the answer arrived with no stream to read\",\n \"The route streams NDJSON. A response with no body means a proxy buffered or \" +\n \"stripped it — check for a gateway that does not pass streaming responses.\",\n );\n }\n let text = \"\";\n let coverage: MeetAnswerCoverage | null = null;\n let failure: ServerRefusal | null = null;\n for await (const envelope of readMatrxNdjsonStream(\n body,\n signal !== undefined ? { signal } : {},\n )) {\n if (envelope.event === MEET_ANSWER_EVENTS.chunk) {\n const piece = readText(envelope.data);\n if (piece.length > 0) {\n // THE ANSWER IS THE CONCATENATED CHUNKS — the server deliberately\n // sends no second copy in a terminal payload, so this accumulation\n // IS the answer, not an optimization.\n text += piece;\n onText?.(text);\n }\n continue;\n }\n if (envelope.event === MEET_ANSWER_EVENTS.info) {\n const parsed = readCoverage(envelope.data);\n if (parsed !== null) coverage = parsed;\n continue;\n }\n if (envelope.event === MEET_ANSWER_EVENTS.phase) {\n const phase = readText(envelope.data);\n onPhase?.(phase.length > 0 ? phase : String(envelope.data));\n continue;\n }\n if (envelope.event === MEET_ANSWER_EVENTS.error) {\n failure = readServerRefusal(envelope.data);\n }\n }\n if (failure !== null) {\n throw new MeetError(\n \"transport\",\n failure.reason,\n failure.remedy.length > 0\n ? failure.remedy\n : \"The answer stopped mid-stream and the server said why. Ask again once the \" +\n \"named cause is cleared.\",\n );\n }\n if (text.trim().length === 0) {\n throw new MeetError(\n \"invalid-response\",\n \"meet.ai.ask: the stream ended with no answer in it\",\n \"Nothing was returned to show. Check the meeting has a Holder bound to \" +\n \"`meet.live_intelligence` at /mandates, then ask again.\",\n );\n }\n return { text: text.trim(), coverage };\n },\n\n startNoteTaker: ({ meetingId, roomName }) =>\n dispatch(\n MEET_ROUTES.noteTakerStart,\n {\n // NO agent_id. Which agent transcribes is the server's business\n // (D2) — this package could not name one if it wanted to.\n meeting_id: meetingId,\n room_name: roomName,\n organization_id: options.api.organizationId,\n },\n \"meet.ai.startNoteTaker\",\n ),\n\n stopNoteTaker: ({ meetingId }) =>\n dispatch(\n MEET_ROUTES.noteTakerStop,\n { meeting_id: meetingId },\n \"meet.ai.stopNoteTaker\",\n ),\n };\n}\n","/**\n * ONE error classification for the whole package (C22).\n *\n * The banned alternative is a host catching a LiveKit or PostgREST error and\n * deciding for itself whether the camera is busy, the token expired, or the\n * meeting is locked — which is how the same five-branch `if` gets copy-pasted\n * into every consumer and drifts. Everything this package throws is a\n * `MeetError` with a stable `code` and a `remedy` SENTENCE. Nothing fails\n * silently, and nothing fails without saying what to do about it.\n *\n * The device codes exist because \"it doesn't work\" in a video product is almost\n * always one of four specific, differently-remediable things: permission\n * denied, no such device, device already in use by another app, or insecure\n * context (http, where `getUserMedia` does not exist at all). A single\n * \"media-error\" would make the UI say the wrong sentence three times out of\n * four.\n */\n\nexport type MeetErrorCode =\n | \"session-unavailable\"\n | \"forbidden\"\n | \"not-found\"\n | \"conflict\"\n | \"token\"\n | \"transport\"\n | \"invalid-response\"\n | \"misconfigured\"\n | \"permission-denied\"\n | \"device-not-found\"\n | \"device-in-use\"\n | \"insecure-context\"\n | \"media-unsupported\"\n | \"room-locked\"\n | \"lobby-denied\"\n | \"capacity\"\n /** Meet wave 1: the meeting was cancelled — its link resolves, its room never opens. */\n | \"cancelled\"\n | \"unknown\";\n\nexport class MeetError extends Error {\n readonly code: MeetErrorCode;\n /** What to DO. Rendered to the user for the device codes. */\n readonly remedy: string;\n override readonly cause?: unknown;\n\n constructor(code: MeetErrorCode, message: string, remedy: string, cause?: unknown) {\n super(message);\n this.name = \"MeetError\";\n this.code = code;\n this.remedy = remedy;\n if (cause !== undefined) this.cause = cause;\n }\n\n /** True when retrying after the host re-establishes a session is the fix. */\n get isRetryable(): boolean {\n return (\n this.code === \"session-unavailable\" ||\n this.code === \"transport\" ||\n this.code === \"token\"\n );\n }\n\n /** True when the user, not the code, must act — the UI shows `remedy`. */\n get isUserActionable(): boolean {\n return (\n this.code === \"permission-denied\" ||\n this.code === \"device-not-found\" ||\n this.code === \"device-in-use\" ||\n this.code === \"insecure-context\"\n );\n }\n}\n\ninterface ErrorLike {\n name?: string | undefined;\n message?: string | undefined;\n code?: string | undefined;\n}\n\nconst FORBIDDEN_CODES = new Set([\"42501\", \"PGRST301\", \"PGRST302\"]);\nconst NOT_FOUND_CODES = new Set([\"PGRST116\", \"PGRST205\"]);\n// 40001: the row changed since the caller read it (meet_update_meeting's version\n// compare-and-swap). 55000: the object is in a state that refuses the change (a\n// cancelled meeting). Both are conflicts a person resolves by reloading.\nconst CONFLICT_CODES = new Set([\"23505\", \"40001\", \"55000\"]);\n\nconst SESSION_MARKERS = [\n \"auth session missing\",\n \"jwt expired\",\n \"no api key found\",\n \"refresh_token_not_found\",\n \"invalid claim: missing sub claim\",\n];\n\n/**\n * THE ONE PLACE a raw database/transport error becomes a typed one. Called at\n * every repository boundary; nothing else in the package inspects a raw error,\n * and no consumer should ever have to.\n */\nexport function normalizeMeetError(error: unknown, operation: string): MeetError {\n if (error instanceof MeetError) return error;\n\n const raw = (error ?? {}) as ErrorLike;\n const message = typeof raw.message === \"string\" ? raw.message : String(error);\n const code = typeof raw.code === \"string\" ? raw.code : undefined;\n const lowered = message.toLowerCase();\n\n if (raw.name === \"SessionUnavailableError\" || SESSION_MARKERS.some((m) => lowered.includes(m))) {\n return new MeetError(\n \"session-unavailable\",\n `${operation}: no Supabase session available (${message})`,\n \"Normal during sign-in and token refresh. The package retries once after the host's \" +\n \"session source resolves; log it as a warning, never as an error.\",\n error,\n );\n }\n if (code !== undefined && FORBIDDEN_CODES.has(code)) {\n return new MeetError(\n \"forbidden\",\n `${operation}: denied by the database (${code}: ${message})`,\n \"Authorization is RLS plus auth-checked RPCs (R5). Fix the policy or the caller's \" +\n \"membership — never route around it with a service-role client in a browser.\",\n error,\n );\n }\n if (code !== undefined && NOT_FOUND_CODES.has(code)) {\n return new MeetError(\n \"not-found\",\n `${operation}: not found (${code}: ${message})`,\n \"The row is gone, or RLS hides it. If this is PGRST205 the communication.meet_* tables \" +\n \"are not deployed yet — see MEET_SCHEMA in repository.ts for the exact contract.\",\n error,\n );\n }\n if (code !== undefined && CONFLICT_CODES.has(code)) {\n return new MeetError(\n \"conflict\",\n `${operation}: unique violation (${code}: ${message})`,\n \"A concurrent writer won. Re-read the meeting rather than retrying the insert — for a \" +\n \"call invite this is the idempotency key doing its job.\",\n error,\n );\n }\n return new MeetError(\n \"transport\",\n `${operation}: ${message}`,\n \"Transient transport failure. Reads retry once; a join failure surfaces to the room \" +\n \"phase as `failed` with this message rather than hanging on a spinner.\",\n error,\n );\n}\n\n/**\n * THE DEVICE ERROR TRANSLATOR — the second-most-copied block in every video app.\n *\n * `getUserMedia` rejects with DOMException names, and every one of them means\n * something a user could fix if we told them. This is the whole reason the\n * device layer lives in the package (C22 test 3: less-than-perfect unless done\n * perfectly).\n */\nexport function normalizeDeviceError(error: unknown, operation: string): MeetError {\n if (error instanceof MeetError) return error;\n const raw = (error ?? {}) as ErrorLike;\n const name = raw.name ?? \"\";\n const message = typeof raw.message === \"string\" ? raw.message : String(error);\n\n switch (name) {\n case \"NotAllowedError\":\n case \"SecurityError\":\n return new MeetError(\n \"permission-denied\",\n `${operation}: camera/microphone permission denied`,\n \"Allow camera and microphone access for this site, then rejoin. On macOS also check \" +\n \"System Settings › Privacy & Security — a browser denied there shows the same error.\",\n error,\n );\n case \"NotFoundError\":\n case \"OverconstrainedError\":\n return new MeetError(\n \"device-not-found\",\n `${operation}: no matching camera/microphone (${message})`,\n \"The selected device is gone — usually an unplugged headset. Pick another device in \" +\n \"the pre-join panel; the package falls back to the system default automatically.\",\n error,\n );\n case \"NotReadableError\":\n case \"AbortError\":\n return new MeetError(\n \"device-in-use\",\n `${operation}: the device is already in use (${message})`,\n \"Another application (or another tab) holds the camera. Close it and try again — the \" +\n \"hardware, not the meeting, is what refused.\",\n error,\n );\n case \"TypeError\":\n return new MeetError(\n \"insecure-context\",\n `${operation}: media devices are unavailable in this context (${message})`,\n \"getUserMedia only exists on https or localhost. Serve the app over https.\",\n error,\n );\n default:\n return new MeetError(\n \"media-unsupported\",\n `${operation}: ${message}`,\n \"This browser refused the media request for a reason the package does not recognize. \" +\n \"Report it with this message so the class gets a named remedy rather than a shrug.\",\n error,\n );\n }\n}\n\n/** A response whose SHAPE is wrong — the ingress boundary, not the wire. */\nexport function invalidResponse(operation: string, detail: string): MeetError {\n return new MeetError(\n \"invalid-response\",\n `${operation}: ${detail}`,\n \"The server returned a shape this package does not accept. Rendering it would put a lie \" +\n \"on the screen, so it is refused here. Fix the endpoint's return contract.\",\n );\n}\n","/**\n * THE TOKEN FLOW — the ONLY authorization path into a room (R1).\n *\n * 🚨 **THE CLIENT NEVER HOLDS A LIVEKIT SECRET.** Not in an env var, not in a\n * build-time constant, not \"just for local dev\". A LiveKit API secret in a\n * browser bundle mints a token for ANY room in the project, including one the\n * holder was never invited to — it is a full compromise of every meeting in the\n * organization. This package therefore has no code path that could accept one:\n * it asks aidream, and aidream mints.\n *\n * Four hard parts live here so no host reimplements them (C22):\n *\n * 1. **Single flight.** A React strict-mode double effect, a re-render, and a\n * reconnect all ask at once; they share ONE request. Two tokens for one\n * identity is not harmless — LiveKit disconnects the older session, which\n * looks exactly like \"my call randomly drops when I open the tab\".\n * 2. **Expiry is honored BEFORE it bites.** A token is refreshed at 80% of its\n * life, not when a reconnect fails at 100%. A meeting that outlives its\n * token and cannot reconnect is the classic 2-hour-meeting bug.\n * 3. **Guests are first-class, not an exception.** A guest has no session and\n * the request carries a display name instead; the SERVER decides what a\n * guest may do. There is no client-side \"is this person allowed\" branch.\n * 4. **A missing session is a lifecycle moment.** Between sign-in and token\n * arrival, the fetch retries ONCE after the host's session resolves and then\n * reports `session-unavailable` as a warning — never a red error, never a\n * retry storm.\n */\n\nimport type { MeetApi } from \"./api\";\nimport { invalidResponse, MeetError } from \"./errors\";\nimport type {\n MeetIdentity,\n ParticipantIdentity,\n ParticipantRole,\n RoomName,\n} from \"./types\";\n\nexport interface RoomToken {\n readonly token: string;\n readonly serverUrl: string;\n readonly roomName: RoomName;\n readonly identity: ParticipantIdentity;\n readonly displayName: string;\n /** ISO. The package refreshes at 80% of the remaining life. */\n readonly expiresAt: string;\n /** What the SERVER granted. The client renders from this; it never decides. */\n readonly canPublish: boolean;\n readonly canSubscribe: boolean;\n readonly canRecord: boolean;\n readonly isHost: boolean;\n /**\n * 🚨 THE SERVER'S WORD ON WHO THIS JOINER IS (MRI-A11) — `host`,\n * `participant` or `guest`, minted from `host_user_id` or a real iam grant.\n * The same string is minted into the LiveKit token's participant metadata and\n * its `matrx.participant.role` attribute, so the roster and this response\n * cannot disagree. A server that predates MRI-A11 sends no role, and the\n * fallback below reads the older `is_host` boolean rather than pretending.\n */\n readonly role: ParticipantRole;\n /** True when the server put this joiner in the lobby (D6). */\n readonly lobby: boolean;\n}\n\nexport type { AccessTokenSource } from \"./api\";\n\nexport interface TokenClientOptions {\n /** The ONE org-aware aidream client (MRI-A16). Owns base url and headers. */\n api: MeetApi;\n /** Injected clock, so expiry logic is provable without waiting two hours. */\n now?: (() => number) | undefined;\n /**\n * Where a GUEST's pass survives a page close (MRF-1). Absent means passes\n * live only in memory, which is correct for a member (they have a session to\n * mint a new one from) and is why this is optional rather than assumed.\n */\n storage?: RoomTokenStorage | undefined;\n}\n\n/**\n * 🚨 **WHY A GUEST'S PASS MUST OUTLIVE THE TAB (MRF-1).**\n *\n * A guest has no session, so their only credential for a meeting is the room\n * token this server minted for them. After the meeting ends, `/token` refuses\n * to mint another one — correctly: the room is gone and nobody may rejoin it.\n * So a guest who closes the tab and comes back to read the summary has, in a\n * purely in-memory client, *no way to prove they were ever there* — and the one\n * honest thing left to show them is a refusal.\n *\n * Persisting the pass is what makes the durable link durable for them. It is\n * per-device by nature (it is stored beside the device id that minted it) and\n * it expires on its own: `meet.room_token_ttl_seconds` is the organization's\n * setting for how long, and an expired pass produces the renew-the-link\n * sentence, never \"you were never here\".\n */\nexport interface RoomTokenStorage {\n read(roomName: RoomName): string | null;\n write(roomName: RoomName, serialized: string): void;\n remove(roomName: RoomName): void;\n}\n\n/** `localStorage` when it exists; a no-op that SAYS so otherwise. */\nexport function createWebRoomTokenStorage(\n onDiagnostic?: (message: string, remedy: string) => void,\n): RoomTokenStorage {\n const store = (globalThis as { localStorage?: Storage }).localStorage;\n const key = (roomName: RoomName): string => `mx.meet.pass.${roomName}`;\n if (store === undefined) {\n // NEVER SILENT. A guest in a browser with no storage will be refused the\n // record after they close the tab, and that is worth a line rather than a\n // mystery.\n onDiagnostic?.(\n \"This browser exposes no localStorage, so a guest's meeting pass cannot be kept.\",\n \"A guest who closes the tab will have to open the meeting link again before the \" +\n \"record opens. Signed-in members are unaffected.\",\n );\n return { read: () => null, write: () => undefined, remove: () => undefined };\n }\n return {\n read(roomName) {\n try {\n return store.getItem(key(roomName));\n } catch {\n return null;\n }\n },\n write(roomName, serialized) {\n try {\n store.setItem(key(roomName), serialized);\n } catch {\n /* a full or blocked store is a lost convenience, never a lost join */\n }\n },\n remove(roomName) {\n try {\n store.removeItem(key(roomName));\n } catch {\n /* see write */\n }\n },\n };\n}\n\nexport interface TokenRequest {\n readonly roomName: RoomName;\n readonly identity: MeetIdentity;\n /** Present for a meeting join; absent for an ad-hoc call room. */\n readonly meetingId?: string | undefined;\n /** The public meeting slug, when joining by link without knowing the id. */\n readonly slug?: string | undefined;\n}\n\nexport interface TokenClient {\n /** A currently-valid token, minting or refreshing only when it must. */\n get(request: TokenRequest): Promise<RoomToken>;\n /** Drop the cached token for a room (after a `denied`, or on leave). */\n invalidate(roomName: RoomName): void;\n /** True when the cached token is inside its refresh window. */\n needsRefresh(roomName: RoomName): boolean;\n /**\n * The pass this DEVICE holds for a room, **including an expired one** (MRF-1).\n *\n * 🚨 The expired case is the whole reason this returns the token instead of\n * `null`: \"your pass expired, open the link again\" and \"you were never in\n * this meeting\" are different sentences, and only the caller that can see the\n * expiry can say the right one. Never used to join — `get` mints for that.\n */\n remembered(roomName: RoomName): RoomToken | null;\n}\n\n/** The aidream routes this package calls. ONE place, so a rename is one edit. */\n/**\n * EVERY aidream ROUTE THIS PACKAGE CALLS, in one object.\n *\n * This is the contract in both directions: aidream carries a test\n * (`services/meet/tests/test_meet_service.py`) that reads THIS object out of\n * this source file and fails if the server stops serving one of these paths.\n * The package is the spec.\n *\n * `meetingEnd` is pinned here BEFORE the server serves it (MRI-A6 owns landing\n * it). That is deliberate and it is not a lie on screen: the control that calls\n * it renders, and a 404 from a server that has not landed A6 is reported as the\n * honest sentence \"Ending a meeting is not available on this server yet\" —\n * never a dead button, never a spinner, and never a silent no-op.\n */\nexport const MEET_ROUTES = {\n token: \"/api/v1/meet/token\",\n recordingStart: \"/api/v1/meet/recording/start\",\n recordingStop: \"/api/v1/meet/recording/stop\",\n noteTakerStart: \"/api/v1/meet/agent/start\",\n noteTakerStop: \"/api/v1/meet/agent/stop\",\n /** In-meeting Q&A. Streams NDJSON; body is `{meeting_id, question}` only. */\n intelligenceAsk: \"/api/v1/meet/intelligence/ask\",\n /** A host ends the meeting for everyone. Served by MRI-A6. */\n meetingEnd: \"/api/v1/meet/end\",\n /**\n * THE POST-MEETING RECORD FOR A READER WITH NO DATABASE (MRF-1). A `GET`,\n * authorized by the room token this device already holds, carried in the\n * `x-meet-room-token` header — never a query parameter, because a bearer\n * credential in a URL lands in access logs, referrers and history.\n */\n record: \"/api/v1/meet/record\",\n /** A host chooses what guests may read of ONE meeting (MRF-1). */\n recordAccess: \"/api/v1/meet/record/access\",\n /**\n * Meet wave 1 (0.8): bring every invitee up to date after a write — sends the\n * invitation / update / cancellation emails with their `.ics` and re-queues\n * reminders. Idempotent. `{meeting_id}` is substituted by `meetingPath`.\n */\n meetingAnnounce: \"/api/v1/meet/meetings/{meeting_id}/announce\",\n /** Put a one-off meeting on the caller's own Google Calendar (gated by the server). */\n meetingGoogleCalendar: \"/api/v1/meet/meetings/{meeting_id}/google-calendar\",\n /**\n * Meet wave 3: the recap email after the meeting. `GET` = the draft (subject,\n * body from the wrap-up, who it can go to); `POST` = send what the host\n * reviewed (`dry_run` renders and queues nothing). Never sent automatically.\n */\n meetingFollowUp: \"/api/v1/meet/meetings/{meeting_id}/follow-up\",\n /**\n * Meet wave 2: EVERY in-meeting host power (mute, stop video, mute all, ask to\n * unmute, spotlight, lower hands, co-host, hand over, rename, remove, report).\n * Decided by the server from the meeting itself; a guest's pass rides\n * `x-meet-room-token`.\n */\n moderate: \"/api/v1/meet/moderate\",\n /** Meet wave 2: the SAVED chat — `POST` sends to everyone, `GET ?meeting_id=` reads history. */\n chat: \"/api/v1/meet/chat\",\n} as const;\n\n/** A `MEET_ROUTES` template with its `{meeting_id}` filled in, URL-encoded. */\nexport function meetingPath(template: string, meetingId: string): string {\n return template.replace(\"{meeting_id}\", encodeURIComponent(meetingId));\n}\n\n/** The header the guest's pass rides on. Pinned on both sides. */\nexport const ROOM_TOKEN_HEADER = \"x-meet-room-token\";\n\n/** Refresh at 80% of the token's life — never at the moment it dies. */\nconst REFRESH_RATIO = 0.8;\n\ninterface CacheEntry {\n token: RoomToken;\n mintedAt: number;\n inFlight: Promise<RoomToken> | null;\n}\n\nfunction readString(source: Record<string, unknown>, key: string): string | null {\n const value = source[key];\n return typeof value === \"string\" && value.length > 0 ? value : null;\n}\n\nfunction readBoolean(source: Record<string, unknown>, key: string, fallback: boolean): boolean {\n const value = source[key];\n return typeof value === \"boolean\" ? value : fallback;\n}\n\nconst TOKEN_ROLES: readonly ParticipantRole[] = [\"host\", \"cohost\", \"participant\", \"guest\"];\n\n/** A word this package does not know grants nothing — it is not a host. */\nfunction readRole(source: Record<string, unknown>, key: string): ParticipantRole | null {\n const value = source[key];\n return TOKEN_ROLES.includes(value as ParticipantRole) ? (value as ParticipantRole) : null;\n}\n\nexport function parseRoomToken(body: unknown, roomName: RoomName): RoomToken {\n if (typeof body !== \"object\" || body === null) {\n throw invalidResponse(\"meet.token\", \"the response body was not an object\");\n }\n const envelope = body as Record<string, unknown>;\n // aidream's ordinary envelope is `{ success, data, msg }`; a bare object is\n // accepted too so a self-hosted route does not have to imitate it.\n const payload =\n typeof envelope[\"data\"] === \"object\" && envelope[\"data\"] !== null\n ? (envelope[\"data\"] as Record<string, unknown>)\n : envelope;\n\n const isHost = readBoolean(payload, \"is_host\", false);\n const token = readString(payload, \"token\");\n const serverUrl = readString(payload, \"server_url\") ?? readString(payload, \"serverUrl\");\n const identity = readString(payload, \"identity\");\n const expiresAt = readString(payload, \"expires_at\") ?? readString(payload, \"expiresAt\");\n\n if (token === null || serverUrl === null || identity === null) {\n throw invalidResponse(\n \"meet.token\",\n \"the response is missing token, server_url, or identity — joining with a partial \" +\n \"token would fail inside LiveKit with an opaque error instead of here\",\n );\n }\n if (expiresAt === null) {\n throw invalidResponse(\n \"meet.token\",\n \"the response carries no expires_at. Without it the package cannot refresh before \" +\n \"the token dies, and a long meeting silently loses its ability to reconnect\",\n );\n }\n return {\n token,\n serverUrl,\n roomName,\n identity: identity as ParticipantIdentity,\n displayName: readString(payload, \"display_name\") ?? readString(payload, \"displayName\") ?? identity,\n expiresAt,\n canPublish: readBoolean(payload, \"can_publish\", true),\n canSubscribe: readBoolean(payload, \"can_subscribe\", true),\n canRecord: readBoolean(payload, \"can_record\", false),\n isHost,\n // An older server sends `is_host` and no `role`; a guest join sends neither.\n // Deriving the role from what DID arrive keeps a host a host against a\n // server that has not landed MRI-A11 — and never invents a host from\n // silence, because both fallbacks below grant nothing.\n role:\n readRole(payload, \"role\") ??\n (isHost ? \"host\" : identity.startsWith(\"guest:\") ? \"guest\" : \"participant\"),\n lobby: readBoolean(payload, \"lobby\", false),\n };\n}\n\nexport function createTokenClient(options: TokenClientOptions): TokenClient {\n const cache = new Map<RoomName, CacheEntry>();\n const now = options.now ?? (() => Date.now());\n const storage = options.storage;\n\n /** A GUEST's pass is kept; a member's is not — they can always mint again. */\n function remember(token: RoomToken): void {\n if (storage === undefined) return;\n if (!token.identity.startsWith(\"guest:\")) return;\n storage.write(token.roomName, JSON.stringify(token));\n }\n\n function recall(roomName: RoomName): RoomToken | null {\n if (storage === undefined) return null;\n const raw = storage.read(roomName);\n if (raw === null) return null;\n try {\n const parsed = JSON.parse(raw) as RoomToken;\n // A stored blob that is not a pass for THIS room proves nothing, and a\n // half-written one must not be handed out as a credential.\n if (typeof parsed.token !== \"string\" || parsed.token.length === 0) return null;\n if (parsed.roomName !== roomName) return null;\n return parsed;\n } catch {\n storage.remove(roomName);\n return null;\n }\n }\n\n function expired(entry: CacheEntry): boolean {\n const expiry = Date.parse(entry.token.expiresAt);\n if (Number.isNaN(expiry)) return true;\n const life = expiry - entry.mintedAt;\n if (life <= 0) return true;\n return now() >= entry.mintedAt + life * REFRESH_RATIO;\n }\n\n async function request(input: TokenRequest, retryOnMissingSession: boolean): Promise<RoomToken> {\n const guest = input.identity.userId === null;\n let response: Response;\n try {\n // THE ORGANIZATION IS A HEADER, NOT ONLY A BODY FIELD — and it is put\n // there by `core/api.ts`, the one client, so no caller can forget it\n // (MRI-A16). A body-only `organization_id` looked right and never\n // arrived: the org-admission middleware refuses first, 400, before the\n // meet router is ever reached.\n response = await options.api.request({\n path: MEET_ROUTES.token,\n method: \"POST\",\n // A GUEST HAS NO SESSION AND IS STILL A FIRST-CLASS JOINER (D6), so\n // only an authenticated join requires one.\n requireAuth: !guest,\n operation: \"meet.token\",\n body: {\n room_name: input.roomName,\n ...(input.meetingId !== undefined ? { meeting_id: input.meetingId } : {}),\n ...(input.slug !== undefined ? { slug: input.slug } : {}),\n organization_id: input.identity.organizationId,\n display_name: input.identity.displayName,\n device_id: input.identity.deviceId,\n guest,\n },\n });\n } catch (error) {\n if (\n retryOnMissingSession &&\n (error as { code?: string }).code === \"session-unavailable\"\n ) {\n // ONE retry, after the host's session source has had a turn. This is\n // the cure for \"909 captured errors in 0.6 seconds\": a read that lands\n // between sign-in and token arrival is a lifecycle moment.\n await Promise.resolve();\n return request(input, false);\n }\n throw error;\n }\n\n if (response.status === 401 || response.status === 403) {\n // THE SERVER'S SENTENCE IS THE ONE A PERSON READS. aidream answers every\n // refusal with `{ message, remedy }` (\"The host did not admit you…\", \"A host\n // removed you…\"); the fallback only covers a body that says nothing.\n const said = await serverSentence(response);\n throw new MeetError(\n \"forbidden\",\n said?.message ?? \"You can't join this meeting.\",\n said?.remedy ??\n \"Ask the person who shared the link to let you in, then open the link again.\",\n );\n }\n if (response.status === 404) {\n throw new MeetError(\n \"not-found\",\n \"meet.token: no such meeting\",\n \"The link is wrong or the meeting was deleted. Show the 'meeting not found' screen; \" +\n \"a durable link that 404s is never a retry.\",\n );\n }\n if (response.status === 410) {\n // Meet wave 1: a CANCELLED meeting. The link resolves; the room never opens.\n // The server's own sentence (with the host's reason) is the message.\n const reason = (await serverSentence(response))?.message ?? \"This meeting was cancelled.\";\n throw new MeetError(\n \"cancelled\",\n reason,\n \"Nobody can join a cancelled meeting. Show the cancelled screen with this sentence; \" +\n \"ask the host to schedule a new one.\",\n );\n }\n if (response.status === 423) {\n const said = await serverSentence(response);\n throw new MeetError(\n \"room-locked\",\n said?.message ?? \"The meeting is locked.\",\n said?.remedy ??\n \"The host locked the room. Ask them to unlock it, then join again.\",\n );\n }\n if (response.status === 503) {\n throw new MeetError(\n \"misconfigured\",\n \"meet.token: the meeting service is not configured\",\n \"aidream is missing LIVEKIT_URL / LIVEKIT_API_KEY / LIVEKIT_API_SECRET. That is a \" +\n \"server deployment fix; the client cannot and must not supply them.\",\n );\n }\n if (!response.ok) {\n throw new MeetError(\n \"token\",\n `meet.token: the server returned ${response.status}`,\n \"Transient. The package retries the join once; if it persists check aidream's meet \" +\n \"router logs for the room name in question.\",\n );\n }\n\n return parseRoomToken(await response.json(), input.roomName);\n }\n\n return {\n get(input) {\n const entry = cache.get(input.roomName);\n if (entry !== undefined) {\n if (entry.inFlight !== null) return entry.inFlight;\n if (!expired(entry)) return Promise.resolve(entry.token);\n }\n // SINGLE FLIGHT. Every concurrent caller shares this promise, so a strict\n // mode double-mount cannot mint two tokens for one identity.\n const pending = request(input, true)\n .then((token) => {\n cache.set(input.roomName, { token, mintedAt: now(), inFlight: null });\n // MRF-1: kept HERE, at the one place a pass is ever minted, so no\n // future caller can acquire one without it being remembered.\n remember(token);\n return token;\n })\n .catch((error: unknown) => {\n // A failure is NEVER cached — one wobble would otherwise leave the\n // room unjoinable until a reload.\n cache.delete(input.roomName);\n throw error;\n });\n cache.set(input.roomName, {\n token: entry?.token ?? placeholder(input.roomName),\n mintedAt: entry?.mintedAt ?? now(),\n inFlight: pending,\n });\n return pending;\n },\n invalidate(roomName) {\n cache.delete(roomName);\n // 🚨 THE STORED PASS SURVIVES `invalidate` ON PURPOSE. This is called on\n // leave and after a refused mint, and a guest leaving a meeting is\n // exactly the person who comes back to read its summary. What `get`\n // refuses to REUSE and what the record read may PRESENT are two different\n // questions; clearing the pass here would answer the second one wrong.\n },\n needsRefresh(roomName) {\n const entry = cache.get(roomName);\n return entry === undefined || expired(entry);\n },\n remembered(roomName) {\n // The in-flight `placeholder()` occupies the cache slot with an EMPTY\n // token string and is never handed out — including here, where handing it\n // out would present \"\" as a credential and earn a 403 that means nothing.\n const live = cache.get(roomName)?.token;\n if (live !== undefined && live.token.length > 0) return live;\n return recall(roomName);\n },\n };\n}\n\n/** Never handed out: it only occupies the slot while a mint is in flight. */\nfunction placeholder(roomName: RoomName): RoomToken {\n return {\n token: \"\",\n serverUrl: \"\",\n roomName,\n identity: \"\" as ParticipantIdentity,\n displayName: \"\",\n expiresAt: new Date(0).toISOString(),\n canPublish: false,\n canSubscribe: false,\n canRecord: false,\n isHost: false,\n role: \"participant\",\n lobby: false,\n };\n}\n\n/**\n * The `{ message, remedy }` aidream puts on a refusal (`MeetError` →\n * `{ error, message, user_message, remedy }`, or FastAPI's `{ detail: {…} }`),\n * or null when the body carries no sentence.\n */\nasync function serverSentence(\n response: Response,\n): Promise<{ message: string; remedy: string | undefined } | null> {\n try {\n const body = (await response.json()) as Record<string, unknown> | null;\n const source =\n body !== null && typeof body.detail === \"object\" && body.detail !== null\n ? (body.detail as Record<string, unknown>)\n : body;\n if (source === null) return null;\n const message =\n typeof source.user_message === \"string\" && source.user_message.trim() !== \"\"\n ? source.user_message\n : typeof source.message === \"string\" && source.message.trim() !== \"\"\n ? source.message\n : null;\n if (message === null) return null;\n const remedy =\n typeof source.remedy === \"string\" && source.remedy.trim() !== \"\" ? source.remedy : undefined;\n return { message, remedy };\n } catch {\n return null;\n }\n}\n","/**\n * THE ONE WAY THIS PACKAGE TALKS TO AIDREAM (MRI-A16).\n *\n * 🚨 **Every request to the aidream server carries `x-organization-id`, and the\n * only way to guarantee \"every\" is for there to be ONE place that builds the\n * request.** aidream's org-admission middleware refuses an authenticated\n * request that does not name the organization it is acting in — 400\n * `organization_required`, before the router is ever reached.\n *\n * 0.1.3 learned that lesson and put the header on the three meet callers by\n * hand. That fixed the instances and left the CLASS wide open, and on\n * 2026-09-09 the class collected its next victim: `<RecordingPlayer>` fetched\n * `GET /files/{id}/download?inline=1` through a bare `fetch` with only a bearer\n * token, so a perfectly landed 1.38 MB recording could not be played by the\n * host who made it (MRI-C8; the identical URL returned `200 video/mp4` the\n * moment the header was added by hand). A fourth caller was written months\n * after the lesson and never heard it, because a lesson written into three call\n * sites is not a lesson, it is three copies of a workaround.\n *\n * So: this module owns the base URL, the organization header and the bearer\n * token, and `api.test.ts` holds a guard that FAILS THE BUILD if any other file\n * in the package calls `fetch(` against a base URL or points an element `src=`\n * at one. A new caller cannot be written without the header any more.\n *\n * 🚨 **HOW A `<video>` GETS ITS BYTES, given that signed URLs are eradicated.**\n * A browser media element cannot attach a header, so a bare\n * `src=\"https://server…/files/{id}/download\"` carries no session and no\n * organization and is refused — which is precisely what MRI-C8 saw. The\n * platform's answer is NOT a signed URL (`aidream/api/routers/files` mints\n * none, by law) but the FILE-SESSION COOKIE: `POST /files/session` mints an\n * HttpOnly `SameSite=None` cookie that the auth middleware accepts on exactly\n * the GET byte-serving routes (`COOKIE_AUTH_PATH_RE` in\n * `matrx_connect/middleware/session_cookie.py`), and a cookie rides a media\n * request that a header cannot. Every private `<img>`/`<video>` in the platform\n * already renders this way.\n *\n * So `fileMedia` mints the cookie and hands back a STREAMING url — which is\n * what lets a person scrub a two-hour recording instead of waiting for a\n * gigabyte to arrive. When the mint is refused (no session, an older server,\n * a browser blocking third-party cookies) it falls back to reading the bytes\n * with the organization header into a `blob:` url — and it SAYS it did, with\n * the reason, because a silent fallback that downloads a gigabyte is exactly\n * the kind of automatic intervention that must announce itself.\n */\n\nimport { MeetError, normalizeMeetError } from \"./errors\";\nimport type { OrganizationId } from \"./types\";\n\n/**\n * How the host tells us who is asking. Returns null before sign-in resolves,\n * and for a guest, who has no session at all and is still a first-class joiner.\n *\n * It lives HERE rather than in `tokens.ts` (where it was born) because this is\n * now the one module that turns a session into a request.\n */\nexport type AccessTokenSource = () => Promise<string | null>;\n\n/** The header aidream's org-admission middleware demands. One definition. */\nexport const ORGANIZATION_HEADER = \"x-organization-id\";\n\nexport interface MeetApiOptions {\n /** aidream's origin. Never a LiveKit or provider URL. */\n baseUrl: string;\n /** Named on EVERY request; the server refuses one that omits it. */\n organizationId: OrganizationId;\n accessToken: AccessTokenSource;\n fetchImpl?: typeof fetch | undefined;\n}\n\nexport interface MeetApiRequest {\n /** An absolute path on the aidream origin, e.g. `/api/v1/meet/token`. */\n path: string;\n method?: \"GET\" | \"POST\" | undefined;\n /** JSON body. Serialized here so no caller can forget the content type. */\n body?: Record<string, unknown> | undefined;\n /**\n * `true` — refuse before the wire when there is no session, with the given\n * operation named. `false` — send whatever session exists, or none (a guest\n * minting a room token is a real, authorized case).\n */\n requireAuth?: boolean | undefined;\n /** Names the caller in every error this raises. */\n operation: string;\n /** Extra headers. May not override the organization header. */\n headers?: Record<string, string> | undefined;\n /**\n * `\"include\"` for the ONE request that mints the file-session cookie — a\n * `Set-Cookie` on a cross-origin response is dropped without it.\n */\n credentials?: RequestCredentials | undefined;\n /** Cancels the request. The Q&A stream is abortable by the person asking. */\n signal?: AbortSignal | undefined;\n}\n\nexport interface MeetApi {\n readonly baseUrl: string;\n readonly organizationId: OrganizationId;\n /** The URL a request to `path` would go to. For diagnostics, never for fetching. */\n url(path: string): string;\n /** One request, with the organization header and the session already on it. */\n request(input: MeetApiRequest): Promise<Response>;\n /**\n * Read an authenticated file into a `blob:` URL an element can load. The\n * caller MUST `URL.revokeObjectURL` it — a leaked one pins the whole file in\n * memory for the life of the tab.\n */\n fetchObjectUrl(input: MeetApiRequest): Promise<string>;\n /**\n * A url a `<video>`/`<img>` can load for a platform file. Streams when the\n * file-session cookie can be minted; otherwise reads the bytes with the\n * organization header and says why it had to.\n */\n fileMedia(fileId: string, operation: string): Promise<MeetFileMedia>;\n /** Re-mint the file-session cookie. Returns whether it now exists. */\n refreshFileSession(): Promise<boolean>;\n}\n\n/** Where a media element's bytes are coming from, and whether that is plan A. */\nexport interface MeetFileMedia {\n readonly url: string;\n /** `stream` seeks and starts instantly; `bytes` is a fully downloaded blob. */\n readonly kind: \"stream\" | \"bytes\";\n /**\n * Set only for `bytes`, and never null-and-hoping: the sentence a surface\n * shows to explain why it had to download the whole file first.\n */\n readonly fallbackReason: string | null;\n}\n\n/** `POST /files/session` — mints the `mx_files_session` cookie (files law). */\nexport const FILE_SESSION_PATH = \"/files/session\";\n\nexport function createMeetApi(options: MeetApiOptions): MeetApi {\n const doFetch = options.fetchImpl ?? globalThis.fetch;\n const base = options.baseUrl.replace(/\\/+$/, \"\");\n\n async function headersFor(input: MeetApiRequest): Promise<Record<string, string>> {\n const token = await options.accessToken();\n if (token === null && input.requireAuth === true) {\n throw new MeetError(\n \"session-unavailable\",\n `${input.operation}: this request requires a signed-in session`,\n \"Render the signed-out or guest surface rather than a control that will be refused.\",\n );\n }\n return {\n ...(input.headers ?? {}),\n ...(input.body !== undefined ? { \"content-type\": \"application/json\" } : {}),\n // 🚨 LAST, so nothing a caller passes can shadow it.\n [ORGANIZATION_HEADER]: options.organizationId,\n ...(token !== null ? { authorization: `Bearer ${token}` } : {}),\n };\n }\n\n return {\n baseUrl: base,\n organizationId: options.organizationId,\n\n url(path) {\n return `${base}${path}`;\n },\n\n async request(input) {\n const headers = await headersFor(input);\n try {\n return await doFetch(`${base}${input.path}`, {\n method: input.method ?? (input.body !== undefined ? \"POST\" : \"GET\"),\n headers,\n ...(input.credentials !== undefined ? { credentials: input.credentials } : {}),\n ...(input.signal !== undefined ? { signal: input.signal } : {}),\n ...(input.body !== undefined ? { body: JSON.stringify(input.body) } : {}),\n });\n } catch (error) {\n throw normalizeMeetError(error, input.operation);\n }\n },\n\n async fetchObjectUrl(input) {\n const response = await this.request(input);\n if (response.status === 401 || response.status === 403) {\n throw new MeetError(\n \"forbidden\",\n `${input.operation}: you are not allowed to read this file`,\n \"The file is safe — this is a read decision, not a lost file. Sign in with an \" +\n \"account in this meeting's organization and try again.\",\n );\n }\n if (!response.ok) {\n throw new MeetError(\n \"transport\",\n `${input.operation}: the server returned ${response.status}`,\n \"The file itself is unaffected. Try again; if it repeats, the platform files \" +\n \"route is the thing to look at, not the recording.\",\n );\n }\n return URL.createObjectURL(await response.blob());\n },\n\n async refreshFileSession() {\n try {\n const response = await this.request({\n path: FILE_SESSION_PATH,\n method: \"POST\",\n // `Set-Cookie` on a cross-origin response is DROPPED without this.\n credentials: \"include\",\n requireAuth: true,\n operation: \"meet.files.session\",\n });\n return response.ok;\n } catch {\n // A refused mint is a fallback, never a failure: the caller reads the\n // bytes with the header instead and says so.\n return false;\n }\n },\n\n async fileMedia(fileId, operation) {\n const path = fileDownloadPath(fileId);\n if (await this.refreshFileSession()) {\n return { url: `${base}${path}`, kind: \"stream\", fallbackReason: null };\n }\n return {\n url: await this.fetchObjectUrl({ path, operation }),\n kind: \"bytes\",\n fallbackReason:\n \"This file was downloaded in full before playing, because the browser session that \" +\n \"lets it stream could not be established. Downloading can take longer, and seeking \" +\n \"is unavailable until it finishes.\",\n };\n },\n };\n}\n\n/** `GET /files/{id}/download?inline=1` — the platform files route (R3). */\nexport function fileDownloadPath(fileId: string): string {\n return `/files/${encodeURIComponent(fileId)}/download?inline=1`;\n}\n","/**\n * THE MEET CHANNEL NAMESPACES.\n *\n * Zero hand-rolled `.channel(` in this package (the realtime doctrine). Every\n * topic is declared through `@ai-matrx/realtime`'s registry, which refuses a\n * colliding re-declaration.\n *\n * THREE channels, each because it has a different AUDIENCE:\n *\n * - `meet-user` (per user): where a call REACHES you — the ring, the cancel,\n * the \"answered on another device\". You are subscribed to this everywhere the\n * provider is mounted, whether or not you are in a meeting.\n * - `meet-room` (per room): the pre-media room — who is knocking, who was\n * admitted, whether recording started. It carries the moments that happen\n * BEFORE and AFTER media, which LiveKit's own data plane cannot: a guest in\n * the lobby is not in the LiveKit room yet, by construction (D6).\n * - `meet-meeting` (per meeting): the durable record's feed — transcript\n * segments, notes, the recording row going `available` — so a surface that is\n * NOT in the call (a meeting page, an admin console) stays live.\n *\n * 🚨 The in-MEDIA control plane (hand raise, reactions, in-room chat) rides\n * LiveKit data messages, NOT these channels — see `DATA_TOPICS`. Splitting them\n * this way is deliberate: anything that must reach a guest with no Supabase\n * session travels on the media plane, where their room token is the authority.\n */\n\nimport { defineChannelNamespace, type ChannelNamespace } from \"@ai-matrx/realtime\";\nimport { globalSlot } from \"./slot\";\nimport type { MeetingId, RoomName, UserId } from \"./types\";\n\ninterface Namespaces {\n user: ChannelNamespace;\n room: ChannelNamespace;\n meeting: ChannelNamespace;\n}\n\nfunction namespaces(): Namespaces {\n // `defineChannelNamespace` throws on a conflicting re-declaration, so these\n // are created lazily through a `globalThis` slot: with dual ESM/CJS output\n // the module can be evaluated twice in one process, and a second identical\n // declaration must be a no-op rather than a crash.\n return globalSlot<Namespaces>(\"channel-namespaces\", () => ({\n user: defineChannelNamespace({\n namespace: \"meet-user\",\n parts: [\"userId\"],\n description:\n \"One user's calling presence: incoming rings, cancellations, and the \" +\n \"answered-elsewhere signal that stops every other device ringing.\",\n }),\n room: defineChannelNamespace({\n namespace: \"meet-room\",\n parts: [\"roomName\"],\n description:\n \"One media room's out-of-band plane: lobby knocks and admissions, lock \" +\n \"state, and recording state — the moments that happen before a guest is \" +\n \"in the LiveKit room at all.\",\n }),\n meeting: defineChannelNamespace({\n namespace: \"meet-meeting\",\n parts: [\"meetingId\"],\n description:\n \"One meeting record's live feed: transcript segments, AI notes, and the \" +\n \"recording row settling — for surfaces that are not in the call.\",\n }),\n }));\n}\n\nexport function userTopic(userId: UserId): string {\n return namespaces().user.topic({ userId });\n}\n\nexport function roomTopic(roomName: RoomName): string {\n return namespaces().room.topic({ roomName });\n}\n\nexport function meetingTopic(meetingId: MeetingId): string {\n return namespaces().meeting.topic({ meetingId });\n}\n\n/** Broadcast event names. One place, so a sender and a receiver cannot drift. */\nexport const MEET_EVENTS = {\n /** A call is ringing you. Carries the whole invite; no follow-up read. */\n ring: \"mx.call.ring\",\n /** The caller hung up before you answered. */\n cancel: \"mx.call.cancel\",\n /** You answered (or declined) on another device. Stop ringing here. */\n settled: \"mx.call.settled\",\n /** Someone is in the lobby. Hosts render the knock. */\n knock: \"mx.lobby.knock\",\n /** A host decided. The knocker learns it here — they have no DB read. */\n admission: \"mx.lobby.admission\",\n /** The room was locked or unlocked. */\n lock: \"mx.room.lock\",\n /** Recording started or stopped. EVERY participant renders the indicator. */\n recording: \"mx.room.recording\",\n} as const;\n\n/**\n * 🚨 `mx.meeting.transcript` and `mx.meeting.note` WERE declared here and\n * emitted and subscribed by nothing — a broadcast fallback that existed only as\n * a name (MRI-A10 found it; feedback `b25db4d4`). They are gone. The thing they\n * described is real now and lives somewhere better: the platform publishes the\n * durable rows into the LIVEKIT ROOM under `matrx.meet.*` (`core/room-events.ts`,\n * MRI-A12), where a session-less guest's room token is the authority. Sending\n * them over a Supabase broadcast channel would have required the guest to hold a\n * Supabase connection, which is the exact thing they do not have.\n */\n\nexport type MeetEvent = (typeof MEET_EVENTS)[keyof typeof MEET_EVENTS];\n","/**\n * PROCESS-GLOBAL STATE LIVES HERE, NEVER IN A MODULE `let`.\n *\n * With `splitting: false` dual ESM/CJS output, one module can be instantiated\n * TWICE in a single process (a Next.js app that imports ESM while its Jest\n * suite requires CJS is the ordinary case). A module-level `let` therefore\n * silently splits into two independent values — which is how the channel\n * namespace registry \"randomly\" re-declares, and how a device-permission cache\n * \"randomly\" forgets what the user already granted.\n *\n * Everything process-global goes through `globalThis` + `Symbol.for`, and the\n * packed-tarball canary proves the slots are shared across module graphs.\n */\nconst NAMESPACE = \"ai-matrx.meet\";\n\nexport function globalSlot<T>(name: string, create: () => T): T {\n const key = Symbol.for(`${NAMESPACE}.${name}`);\n const host = globalThis as Record<symbol, unknown>;\n const existing = host[key];\n if (existing !== undefined) return existing as T;\n const created = create();\n host[key] = created;\n return created;\n}\n\n/** Test-only: drop a slot so a suite can start from a clean registry. */\nexport function resetGlobalSlotForTests(name: string): void {\n const key = Symbol.for(`${NAMESPACE}.${name}`);\n delete (globalThis as Record<symbol, unknown>)[key];\n}\n","/**\n * THE MEET DOMAIN MODEL.\n *\n * D3: an audio call, a video call, and a meeting are ONE thing — a room. An\n * audio call is a room with video off; a meeting is a room plus scheduling,\n * lobby and host metadata. That ruling is expressed here as ONE `MeetRoom`\n * identity carried by both `/calls` and `/meetings`, not as three parallel\n * hierarchies that drift.\n *\n * Identity-bearing values are BRANDED (C22). A `MeetingId` and a `RoomName` are\n * both strings and are NOT interchangeable — passing the meeting's row id where\n * LiveKit wants the room name produces a room nobody else joins, which looks\n * exactly like \"the other person's camera is broken\".\n */\n\ndeclare const brand: unique symbol;\ntype Brand<T, B extends string> = T & { readonly [brand]: B };\n\nexport type MeetingId = Brand<string, \"MeetingId\">;\nexport type CallId = Brand<string, \"CallId\">;\n/** The LiveKit room name. THE MEDIA ROOM KEY — durable for a meeting link. */\nexport type RoomName = Brand<string, \"RoomName\">;\nexport type UserId = Brand<string, \"UserId\">;\nexport type OrganizationId = Brand<string, \"OrganizationId\">;\n/** LiveKit participant identity. `user:<uuid>` or `guest:<opaque>`. */\nexport type ParticipantIdentity = Brand<string, \"ParticipantIdentity\">;\n\nexport const asMeetingId = (value: string): MeetingId => value as MeetingId;\nexport const asCallId = (value: string): CallId => value as CallId;\nexport const asRoomName = (value: string): RoomName => value as RoomName;\nexport const asUserId = (value: string): UserId => value as UserId;\nexport const asOrganizationId = (value: string): OrganizationId =>\n value as OrganizationId;\nexport const asParticipantIdentity = (value: string): ParticipantIdentity =>\n value as ParticipantIdentity;\n\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\nexport type JsonObject = { [key: string]: JsonValue };\n\n/** Audio-only or with video. A call escalates; it never becomes a new call. */\nexport type CallMode = \"audio\" | \"video\";\n\n/**\n * WHO IS IN THE ROOM, as far as authorization is concerned.\n *\n * A guest has no `userId` — by construction, not by convention. Everything that\n * requires authentication (host powers, recording, starting a call) takes a\n * `userId` and therefore cannot compile against a guest identity (D6).\n */\nexport interface MeetIdentity {\n readonly userId: UserId | null;\n readonly organizationId: OrganizationId;\n readonly displayName: string;\n readonly avatarUrl: string | null;\n /** Stable per-device value so a reconnect keeps ONE LiveKit identity. */\n readonly deviceId: string;\n}\n\nexport function isGuest(identity: MeetIdentity): boolean {\n return identity.userId === null;\n}\n\n/**\n * WHO SOMEBODY IS IN A ROOM — the SERVER's word, never this client's (MRI-A11).\n *\n * `host` is `meet_meetings.host_user_id` or a real `iam` grant on the meeting;\n * `participant` is an authenticated member of the meeting's organization;\n * `guest` is a link-follower with no session. Organization membership is\n * TENANCY and never permission, which is why \"member of the org\" lands on\n * `participant` and not on `host`.\n *\n * `cohost` has no server-side minter yet and is kept because the rank ladder\n * below is the thing that stops a co-host from removing the host; the moment a\n * co-host grant exists it slots in without a second vocabulary.\n */\nexport type ParticipantRole = \"host\" | \"cohost\" | \"participant\" | \"guest\";\n\n/** Rank, so \"can this actor do that to that participant\" is one comparison. */\nexport const ROLE_RANK: Readonly<Record<ParticipantRole, number>> = {\n host: 3,\n cohost: 2,\n participant: 1,\n guest: 0,\n};\n\n/**\n * 🚨 THE ONE PREDICATE FOR \"DOES THIS PERSON HOLD HOST POWERS\".\n *\n * Every host control in this package answers this question and no other. It is\n * a pure function of a SERVER-minted role, so there is no path by which a\n * client's own state can grant it anything.\n */\nexport function isHostRole(role: ParticipantRole): boolean {\n return role === \"host\" || role === \"cohost\";\n}\n\n/**\n * THE LOBBY LADDER (D6). A guest link-follower starts `knocking`; the host\n * admits or denies. An authenticated member of the meeting's org is `admitted`\n * on arrival unless the meeting is locked.\n */\nexport type AdmissionState = \"knocking\" | \"admitted\" | \"denied\" | \"removed\";\n\nexport interface LobbyEntry {\n readonly identity: ParticipantIdentity;\n readonly displayName: string;\n readonly avatarUrl: string | null;\n readonly userId: UserId | null;\n readonly state: AdmissionState;\n readonly knockedAt: string;\n readonly decidedAt: string | null;\n readonly decidedBy: UserId | null;\n}\n\nexport type ConnectionQuality = \"excellent\" | \"good\" | \"poor\" | \"lost\" | \"unknown\";\n\n/** One person in the room, as the UI needs them. Media state is a FACT here. */\nexport interface MeetParticipant {\n readonly identity: ParticipantIdentity;\n readonly userId: UserId | null;\n readonly displayName: string;\n readonly avatarUrl: string | null;\n readonly role: ParticipantRole;\n /**\n * Whether the SERVER granted this participant the power to start a recording\n * (MRI-A11). It is not `role === \"host\"`: a meeting whose recording policy is\n * `always-on` is the server's to start and a host may not touch it, and a\n * `disabled` policy grants it to nobody. The client renders this; it never\n * recomputes the policy.\n */\n readonly canRecord: boolean;\n readonly isLocal: boolean;\n readonly isAgent: boolean;\n readonly micEnabled: boolean;\n readonly cameraEnabled: boolean;\n readonly screenSharing: boolean;\n readonly speaking: boolean;\n readonly handRaised: boolean;\n /**\n * When the hand went up (epoch ms), or null. The HAND QUEUE is ordered by it —\n * first raised, first called on (Meet wave 2). Optional so a roster built by a\n * host before 0.8 still type-checks.\n */\n readonly handRaisedAt?: number | null | undefined;\n readonly quality: ConnectionQuality;\n readonly joinedAt: string;\n /**\n * LiveKit participant attributes, verbatim. The note-taker announces itself\n * here (`matrx.agent.consent_notice`), which is how a consent notice can be\n * rendered for a participant whose token metadata this client cannot read.\n */\n readonly attributes: Readonly<Record<string, string>>;\n}\n\nexport type RoomPhase =\n | \"idle\"\n | \"requesting-token\"\n | \"lobby\"\n | \"connecting\"\n | \"connected\"\n | \"reconnecting\"\n | \"left\"\n | \"failed\";\n\nexport type MeetingKind = \"instant\" | \"scheduled\" | \"recurring\";\n\nexport interface MeetingRecord {\n readonly id: MeetingId;\n readonly organizationId: OrganizationId;\n /** Durable: the same room name before, during, and after (R3). */\n readonly roomName: RoomName;\n /** The public slug in a meeting link. Durable for recurring meetings. */\n readonly slug: string;\n readonly title: string;\n readonly kind: MeetingKind;\n readonly hostUserId: UserId;\n readonly scheduledFor: string | null;\n readonly scheduledDurationMinutes: number | null;\n readonly startedAt: string | null;\n readonly endedAt: string | null;\n readonly locked: boolean;\n readonly lobbyEnabled: boolean;\n readonly recordingPolicy: RecordingPolicy;\n readonly aiEnabled: boolean;\n readonly metadata: JsonObject;\n /*\n * ── MEET WAVE 1 — management (0.8). Always present on a row read from the\n * database by this package; optional in the type only so a hand-built\n * fixture from before 0.8 still compiles.\n */\n /** IANA zone the meeting's wall-clock time is authored in (`America/Los_Angeles`). */\n readonly timeZone?: string;\n /** Description / agenda text. */\n readonly agenda?: string | null;\n /** RFC 5545 RRULE subset — one row and one durable link per series. */\n readonly recurrenceRule?: string | null;\n /** Signed-in members and invitees may enter before a host arrives. */\n readonly joinBeforeHost?: boolean;\n /** Cancel is a STATE: the link still resolves and says so; nobody can join. */\n readonly cancelledAt?: string | null;\n readonly cancellationReason?: string | null;\n /** Archived (soft deleted). Restorable by the host or a co-host. */\n readonly deletedAt?: string | null;\n /** iCalendar SEQUENCE — bumped by the database on every reschedule and on cancel. */\n readonly calendarSequence?: number;\n /** Row version, for the compare-and-swap in `updateMeeting`. */\n readonly version?: number;\n}\n\n/* ─────────────────────────────── MEET WAVE 1 — management vocabulary (0.8) */\n\n/** An invitee's answer. `needs_action` = not answered yet (iCalendar NEEDS-ACTION). */\nexport type RsvpState = \"needs_action\" | \"accepted\" | \"declined\" | \"tentative\";\n/** The answers a person can give. */\nexport type RsvpAnswer = Exclude<RsvpState, \"needs_action\">;\n/** A co-host holds host moderation through a real `iam` admin grant on the meeting. */\nexport type InviteeRole = \"invitee\" | \"cohost\";\n\n/** One person a meeting was sent to (`communication.meet_invitees`). */\nexport interface MeetingInvitee {\n readonly id: string;\n readonly meetingId: MeetingId;\n /** Set when the person has an account — they skip the waiting room and answer in-app. */\n readonly userId: UserId | null;\n readonly email: string | null;\n readonly displayName: string | null;\n readonly role: InviteeRole;\n readonly rsvpState: RsvpState;\n readonly respondedAt: string | null;\n readonly rsvpNote: string | null;\n /** The calendar_sequence of the last invitation they were sent; null = never told. */\n readonly lastSentSequence: number | null;\n readonly lastSentAt: string | null;\n}\n\n/** Who to invite: an account (`userId`) or an address (`email`), or both. */\nexport interface InviteeInput {\n readonly userId?: UserId | undefined;\n readonly email?: string | undefined;\n readonly displayName?: string | undefined;\n /** Omit to keep an existing invitee's role; `cohost` needs the host or a co-host. */\n readonly role?: InviteeRole | undefined;\n}\n\n/** Where one occurrence of a meeting stands. */\nexport type OccurrenceState = \"scheduled\" | \"moved\" | \"cancelled\";\n\n/** One occurrence — for a one-off meeting, the meeting itself. */\nexport interface MeetingOccurrence {\n readonly meetingId: MeetingId;\n /** The start the rule generates (iCalendar RECURRENCE-ID). The key for exceptions. */\n readonly originalStart: string;\n /** When it actually happens (differs from `originalStart` only when `moved`). */\n readonly occurrenceStart: string;\n readonly durationMinutes: number | null;\n readonly state: OccurrenceState;\n readonly sequence: number;\n}\n\n/** One row of the Upcoming list — an occurrence plus what the list shows about its meeting. */\nexport interface UpcomingOccurrence extends MeetingOccurrence {\n readonly organizationId: OrganizationId;\n readonly title: string;\n readonly slug: string;\n readonly kind: MeetingKind;\n readonly hostUserId: UserId;\n readonly timeZone: string;\n readonly meetingCancelled: boolean;\n /** The signed-in reader's own answer, when they are an invitee. */\n readonly myRsvp: RsvpState | null;\n /** `host`, `cohost` or `invitee` — null when the reader simply can see it (org member). */\n readonly myRole: \"host\" | InviteeRole | null;\n}\n\n/** An exception row (`communication.meet_occurrence_overrides`). */\nexport interface OccurrenceOverride {\n readonly id: string;\n readonly meetingId: MeetingId;\n readonly originalStart: string;\n readonly state: \"cancelled\" | \"moved\";\n readonly newStart: string | null;\n readonly newDurationMinutes: number | null;\n readonly reason: string | null;\n readonly calendarSequence: number;\n /** Set when the exception was withdrawn (`restore`) and the occurrence is back on schedule. */\n readonly deletedAt: string | null;\n}\n\n/** Settings a meeting carries; unset ones come from the person's / organization's knobs. */\nexport interface MeetingSettings {\n readonly lobbyEnabled?: boolean | undefined;\n readonly recordingPolicy?: RecordingPolicy | undefined;\n readonly aiEnabled?: boolean | undefined;\n readonly joinBeforeHost?: boolean | undefined;\n}\n\n/** A partial edit. `null` clears a clearable field (agenda, recurrence rule, time). */\nexport interface MeetingChanges extends MeetingSettings {\n readonly title?: string | undefined;\n readonly agenda?: string | null | undefined;\n readonly timeZone?: string | undefined;\n readonly scheduledFor?: string | null | undefined;\n readonly scheduledDurationMinutes?: number | null | undefined;\n readonly recurrenceRule?: string | null | undefined;\n}\n\n/** What the emailed RSVP link shows and answers (no account needed). */\nexport type RsvpInvitation =\n | {\n readonly ok: true;\n readonly meeting: {\n readonly title: string;\n readonly slug: string;\n readonly scheduledFor: string | null;\n readonly durationMinutes: number | null;\n readonly timeZone: string;\n readonly agenda: string | null;\n readonly recurrenceRule: string | null;\n readonly cancelledAt: string | null;\n readonly cancellationReason: string | null;\n readonly endedAt: string | null;\n };\n readonly invitee: {\n readonly displayName: string | null;\n readonly email: string | null;\n readonly rsvpState: RsvpState;\n readonly respondedAt: string | null;\n };\n }\n | { readonly ok: false; readonly message: string };\n\n/** Org-configurable, never hardcoded taste (Law 6 / \"opinions become knobs\"). */\nexport type RecordingPolicy = \"disabled\" | \"host-controlled\" | \"always-on\";\n\nexport type RecordingState =\n | \"idle\"\n | \"starting\"\n | \"recording\"\n | \"stopping\"\n | \"processing\"\n | \"available\"\n /** Bytes were purged under retention; notes and transcript remain durable. */\n | \"expired\"\n | \"failed\";\n\n/**\n * WHICH transport last said what the recording is doing (MRI-A16).\n *\n * `local` — this browser's own optimistic `starting`/`stopping`, which is all\n * the indicator ever had through 0.4.7, and the reason it never went solid.\n * `room` — a `matrx.meet.recording` packet, the ONLY feed a guest has.\n * `record` — the durable `meet_recordings` row. It outranks both (D16).\n */\nexport type RecordingSource = \"local\" | \"room\" | \"record\";\n\n/** The server's durable retention receipt; never inferred from a browser clock. */\nexport interface RecordingRetention {\n readonly operationId: string;\n readonly policyId: string;\n readonly policyUpdatedAt: string;\n readonly phase: \"warning\" | \"expired\";\n readonly dueAt: string;\n readonly expiredAt: string | null;\n}\n\nexport interface RecordingRecord {\n readonly id: string;\n readonly meetingId: MeetingId;\n readonly state: RecordingState;\n readonly startedAt: string | null;\n readonly endedAt: string | null;\n readonly startedBy: UserId | null;\n /** The PLATFORM file id. Never a provider URL (R3). */\n readonly fileId: string | null;\n readonly failureReason: string | null;\n /** Present when central retention warned or purged this recording. */\n readonly retention: RecordingRetention | null;\n}\n\n/**\n * WHERE A TRANSCRIPT LINE CAME FROM — and therefore how much it is worth.\n *\n * D16: `lk.transcription` is published by a room participant and its\n * `sender_identity` is client-supplied and unvalidated by LiveKit, so a caption\n * is a HINT — good enough to read live, never good enough to reason from. A\n * `record` line is a durable `meet_transcript_segments` row written server-side\n * by the note-taker: that is the transcript. A record always beats a caption;\n * a caption never overwrites a record.\n */\nexport type TranscriptSource = \"caption\" | \"record\";\n\nexport interface TranscriptSegment {\n readonly id: string;\n readonly meetingId: MeetingId;\n readonly identity: ParticipantIdentity;\n readonly speaker: string;\n readonly text: string;\n readonly startedAt: string;\n /** Interim text is replaced in place by its final; it is never appended. */\n readonly final: boolean;\n readonly source: TranscriptSource;\n /**\n * The `lk.segment_id` this line was captioned under, when known. A durable\n * row carries it too (the worker writes it into the row's metadata), which is\n * what lets a record REPLACE the caption it supersedes rather than doubling it.\n */\n readonly captionId: string | null;\n}\n\n/**\n * SOMEBODY WHO WAS IN THE MEETING — the durable `meet_participants` row, which\n * outlives the LiveKit room (MRI-D2). `MeetParticipant` above is a live tile;\n * THIS is the attendance record a person reads a week later.\n */\nexport interface MeetingAttendee {\n readonly id: string;\n readonly meetingId: MeetingId;\n readonly identity: ParticipantIdentity;\n readonly displayName: string;\n readonly avatarUrl: string | null;\n readonly userId: UserId | null;\n readonly role: ParticipantRole;\n readonly admissionState: AdmissionState;\n readonly isAgent: boolean;\n readonly joinedAt: string | null;\n readonly leftAt: string | null;\n}\n\nexport type MeetingNoteKind = \"note\" | \"decision\" | \"action-item\";\n\n/**\n * ONE ROW OF WHAT THE MEETING DECIDED. `meet_notes.kind` is a live CHECK\n * constraint of exactly three values (D5) — there is no `summary` kind and no\n * `transcript` kind — so the wrap-up summary is a `note` carrying\n * `metadata.role = \"summary\"`, and a live-window note carries `metadata.window`.\n * Both are projected here so the UI never re-reads raw metadata.\n */\nexport interface MeetingNote {\n readonly id: string;\n readonly meetingId: MeetingId;\n readonly text: string;\n readonly createdAt: string;\n readonly kind: MeetingNoteKind;\n /** Set ONLY when the assignee resolved to a real user (D18). */\n readonly assigneeUserId: UserId | null;\n /** Who the item is for, as a person reads it. A guest keeps their name here. */\n readonly assigneeDisplayName: string | null;\n /** `\"summary\"` for the wrap-up; `null` for everything else. */\n readonly role: \"summary\" | null;\n /** The live-notes window index this came out of, when it came from one. */\n readonly window: number | null;\n /**\n * 🚨 THE WRAP-UP IS THE AUTHORITATIVE POST-MEETING SET (D20).\n *\n * A live-notes window and the wrap-up both write decisions and action items,\n * and on production 2026-09-09 meeting `9cb-39f8-782` carried the SAME\n * decision twice — once from the note-taker at 04:43:57 and once from the\n * wrap-up at 04:47:15 — and the record view listed both. A reader cannot tell\n * a repeated decision from two decisions.\n *\n * So when the wrap-up lands, the server MARKS the window-written decisions\n * and action items it supersedes (`metadata.superseded_by` = the wrap-up's\n * run id) and never deletes them: the row is still the timeline of what was\n * known at 04:43. This field carries that marker, and the record view and the\n * assistant panel render only the rows where it is `null`.\n */\n readonly supersededBy: string | null;\n /**\n * WHICH TRANSPORT DELIVERED THIS COPY (MRI-A12). The same durable row reaches\n * a signed-in member twice — once as a `meet_notes` row over Postgres Changes\n * (`\"record\"`) and once as a `matrx.meet.note` packet on the media plane\n * (`\"room\"`), which is the ONLY copy a session-less guest can receive, because\n * `anon` holds no grant on the table (MRI-A10).\n *\n * They carry the same id and the same words, so the store renders one note.\n * Where they could ever disagree, `\"record\"` wins and `\"room\"` never overwrites\n * it — the database is the record and the packet is the courtesy copy. That is\n * the same precedence captions and segments already follow (D16).\n */\n readonly source: \"record\" | \"room\";\n}\n\n/**\n * THE WRAP-UP, ANNOUNCED (MRI-A12). The summary, decisions and action items\n * arrive as ordinary notes; this says the pass that wrote them FINISHED, which\n * is the difference between \"no summary yet\" and \"no summary is coming\".\n *\n * 🚨 It reaches a screen only while the room still exists. `POST /v1/meet/end`\n * deletes the LiveKit room and the wrap-up runs afterwards, so on the ordinary\n * ending path nobody is in the room to be told — the post-meeting record view is\n * where the summary is read. A surface must therefore treat `null` as \"not\n * announced\", never as \"not written\".\n */\nexport interface WrapUpAnnouncement {\n readonly meetingId: MeetingId;\n /** The `meet_notes` ids the pass wrote, in the order it wrote them. */\n readonly noteIds: readonly string[];\n /** How many durable transcript segments it summarized. */\n readonly segmentCount: number;\n readonly at: string;\n}\n\n/**\n * THE NOTE-TAKER'S STATE, as the meeting row records it\n * (`meet_meetings.metadata.note_taker.state`, MRI-A2). Five values and no\n * spinner: a surface renders the state it is in, or the server's refusal.\n *\n * - `absent` — nobody summoned it. The control offers to.\n * - `joining` — dispatched; it has not entered the room yet.\n * - `transcribing` — the server recorded active transcription and the exact\n * deterministic actor is present in the room.\n * - `handoff_pending` — a row that said transcribing no longer has that exact\n * actor in the room. The next state and any missed audio are not inferred.\n * - `ended` — the recorded note-taker stopped. The cause is not inferred.\n */\nexport type NoteTakerState =\n | \"absent\"\n | \"joining\"\n | \"transcribing\"\n | \"handoff_pending\"\n | \"ended\";\n\n/** The lifecycle of a 1:1 or ad-hoc group call (R2). */\nexport type CallState =\n | \"idle\"\n | \"dialing\"\n | \"ringing\"\n | \"connecting\"\n | \"active\"\n | \"declined\"\n | \"missed\"\n | \"busy\"\n | \"cancelled\"\n | \"ended\"\n | \"failed\";\n\nexport interface CallInvite {\n readonly id: CallId;\n readonly organizationId: OrganizationId;\n readonly roomName: RoomName;\n readonly mode: CallMode;\n readonly callerUserId: UserId;\n readonly callerName: string;\n readonly callerAvatarUrl: string | null;\n readonly calleeUserIds: readonly UserId[];\n /** The durable conversation the invite was delivered into, if any. */\n readonly conversationId: string | null;\n readonly createdAt: string;\n readonly expiresAt: string;\n readonly state: CallState;\n readonly declineMessage: string | null;\n}\n\n/** A person the UI can call. Deliberately minimal: hosts already have this. */\nexport interface CallablePerson {\n readonly userId: UserId;\n readonly displayName: string;\n readonly avatarUrl: string | null;\n}\n\nexport type StageLayout = \"grid\" | \"speaker\" | \"sidebar\";\n","/**\n * THE CALL CENTER — ringing, answering, and the six ways a call ends badly.\n *\n * A call reaches you on whatever surface you are on (R2), which is why this is\n * mounted by the provider and not by a call page. It is also why delivery is\n * DUAL by design, not by belt-and-braces nervousness:\n *\n * - **The durable leg** is the invite ROW plus its Postgres Changes event. It\n * survives a reload, a late-joining tab, and a dropped socket, and it is what\n * makes a missed call a fact rather than a lost packet.\n * - **The instant leg** is a broadcast on the callee's user channel, which\n * arrives without a database round trip.\n *\n * Both are deduplicated on the invite id, so a call rings ONCE however it\n * arrives. Neither is a fallback for the other: removing the durable leg loses\n * calls, and removing the instant leg makes ringing feel slow.\n *\n * 🚨 THE FOUR RULES THAT MAKE RINGING SURVIVABLE\n *\n * 1. **A ring always ends.** Every outgoing call arms a timeout that writes\n * `missed`. A ring with no terminal state is a phone that never stops.\n * 2. **Answering on one device stops every other.** The `settled` signal on\n * your OWN user channel silences the other tabs. Without it, answering on a\n * laptop leaves a phone ringing in the room.\n * 3. **Busy is answered, not ignored.** Being in an active call auto-declines\n * with `busy`, so the caller learns something instead of ringing out.\n * 4. **The state machine is a MACHINE.** Transitions are validated: a\n * `declined` call cannot become `active` because a late accept arrived.\n */\n\nimport type { ChannelHandle, RealtimeManager } from \"@ai-matrx/realtime\";\nimport { MEET_EVENTS, userTopic } from \"./channels\";\nimport { MeetError } from \"./errors\";\nimport type { MeetRepository } from \"./repository\";\nimport type { MeetStore } from \"./store\";\nimport {\n asCallId,\n asRoomName,\n type CallId,\n type CallInvite,\n type CallMode,\n type CallState,\n type MeetIdentity,\n type RoomName,\n type UserId,\n} from \"./types\";\n\n/** Which states may follow which. An invalid transition throws, never silently applies. */\nconst TRANSITIONS: Readonly<Record<CallState, readonly CallState[]>> = {\n idle: [\"dialing\", \"ringing\"],\n dialing: [\"ringing\", \"connecting\", \"cancelled\", \"declined\", \"busy\", \"missed\", \"failed\"],\n ringing: [\"connecting\", \"declined\", \"busy\", \"missed\", \"cancelled\", \"failed\"],\n connecting: [\"active\", \"failed\", \"ended\"],\n active: [\"ended\", \"failed\"],\n declined: [],\n missed: [],\n busy: [],\n cancelled: [],\n ended: [],\n failed: [],\n};\n\nexport function canTransition(from: CallState, to: CallState): boolean {\n return TRANSITIONS[from].includes(to);\n}\n\nexport interface CallCenterOptions {\n manager: RealtimeManager;\n repository: MeetRepository;\n store: MeetStore;\n identity: MeetIdentity;\n /** Ring for this long before the call is `missed`. Org knob, not a constant. */\n ringTimeoutMs?: number | undefined;\n onIncoming?: ((invite: CallInvite) => void) | undefined;\n onSettled?: ((invite: CallInvite) => void) | undefined;\n onDiagnostic?: ((event: { level: \"info\" | \"warn\" | \"error\"; message: string; remedy?: string }) => void) | undefined;\n timers?: {\n setTimeout: (run: () => void, ms: number) => unknown;\n clearTimeout: (handle: unknown) => void;\n now: () => number;\n };\n}\n\nexport interface CallCenter {\n /** Subscribe to this user's calling channel. Call once, from the provider. */\n start(): Promise<void>;\n /** Ring someone. Returns the invite the UI shows as \"calling…\". */\n call(args: {\n people: readonly UserId[];\n mode: CallMode;\n conversationId?: string | undefined;\n }): Promise<CallInvite>;\n accept(id: CallId, mode: CallMode): Promise<CallInvite>;\n decline(id: CallId, message?: string): Promise<CallInvite>;\n cancel(id: CallId): Promise<CallInvite>;\n /** Every invite currently ringing this device. */\n incoming(): readonly CallInvite[];\n outgoing(): CallInvite | null;\n /** Feed a ring that arrived through another path (a messaging action chip). */\n ingest(invite: CallInvite): void;\n dispose(): void;\n}\n\nconst DEFAULT_RING_TIMEOUT_MS = 45_000;\n\nexport function createCallCenter(options: CallCenterOptions): CallCenter {\n const { manager, repository, identity } = options;\n const timers = options.timers ?? {\n setTimeout: (run, ms) => setTimeout(run, ms),\n clearTimeout: (handle) => clearTimeout(handle as ReturnType<typeof setTimeout>),\n now: () => Date.now(),\n };\n const ringTimeoutMs = options.ringTimeoutMs ?? DEFAULT_RING_TIMEOUT_MS;\n\n const incoming = new Map<CallId, CallInvite>();\n const timeouts = new Map<CallId, unknown>();\n let outgoing: CallInvite | null = null;\n let channel: ChannelHandle | null = null;\n\n /**\n * Send-only handles on OTHER people's user channels.\n *\n * 🚨 CACHED AND CLOSED, deliberately. Since `@ai-matrx/realtime` 0.2.0 a\n * channel is ref-counted per DECLARED topic, so `manager.open(...).send(...)`\n * without a matching `close()` increments a refcount that is never released —\n * a leaked subscription per ring, forever. One handle per peer, all closed on\n * dispose.\n */\n const outbound = new Map<string, ChannelHandle>();\n\n function to(userId: UserId): ChannelHandle {\n const topic = userTopic(userId);\n const existing = outbound.get(topic);\n if (existing !== undefined) return existing;\n const opened = manager.open({ topic });\n outbound.set(topic, opened);\n return opened;\n }\n\n function report(level: \"info\" | \"warn\" | \"error\", message: string, remedy?: string): void {\n options.onDiagnostic?.(remedy === undefined ? { level, message } : { level, message, remedy });\n }\n\n function requireUser(operation: string): UserId {\n if (identity.userId === null) {\n throw new MeetError(\n \"forbidden\",\n `${operation}: a guest cannot place or receive calls`,\n \"Guests join meetings by link (D6); calling requires an account. Render the join-by-\" +\n \"link path instead of a call button for guest identities.\",\n );\n }\n return identity.userId;\n }\n\n function clearRing(id: CallId): void {\n const handle = timeouts.get(id);\n if (handle !== undefined) {\n timers.clearTimeout(handle);\n timeouts.delete(id);\n }\n }\n\n function settleLocal(invite: CallInvite): void {\n clearRing(invite.id);\n incoming.delete(invite.id);\n if (outgoing !== null && outgoing.id === invite.id) outgoing = invite;\n options.onSettled?.(invite);\n }\n\n function ingest(invite: CallInvite): void {\n // ONE ring per invite, whichever leg arrived first.\n if (incoming.has(invite.id)) return;\n if (invite.state !== \"ringing\" && invite.state !== \"dialing\") return;\n if (identity.userId === null) return;\n if (invite.callerUserId === identity.userId) return;\n\n // RULE 3: busy is ANSWERED. The caller learns why rather than ringing out.\n const phase = options.store.snapshot().phase;\n if (phase === \"connected\" || phase === \"connecting\" || phase === \"reconnecting\") {\n void repository\n .settleCallInvite(invite.id, \"busy\", null)\n .then((settled) => {\n // The CALLER is who needs to know. Sending this on my own topic\n // would tell my other devices something they already worked out and\n // leave the caller ringing out into silence.\n to(settled.callerUserId).send(MEET_EVENTS.settled, settled);\n })\n .catch((error: unknown) => {\n report(\"warn\", `meet.calls: could not report busy — ${String(error)}`,\n \"The caller will ring out and see a missed call. Harmless, but the busy signal \" +\n \"is what makes a second call feel intentional.\");\n });\n return;\n }\n\n incoming.set(invite.id, { ...invite, state: \"ringing\" });\n options.onIncoming?.(invite);\n // RULE 1: every ring ends. Even if the caller vanishes mid-ring.\n timeouts.set(\n invite.id,\n timers.setTimeout(() => {\n const held = incoming.get(invite.id);\n if (held === undefined) return;\n settleLocal({ ...held, state: \"missed\" });\n }, ringTimeoutMs),\n );\n }\n\n return {\n async start() {\n const me = requireUser(\"meet.calls.start\");\n channel = manager.open({\n topic: userTopic(me),\n broadcast: [\n {\n event: MEET_EVENTS.ring,\n onMessage: (message) => {\n ingest(message.data as CallInvite);\n },\n },\n {\n event: MEET_EVENTS.cancel,\n onMessage: (message) => {\n const invite = message.data as CallInvite;\n const held = incoming.get(invite.id);\n if (held === undefined) return;\n settleLocal({ ...held, state: \"cancelled\" });\n },\n },\n {\n event: MEET_EVENTS.settled,\n onMessage: (message) => {\n // RULE 2: answered elsewhere. Stop ringing HERE.\n const invite = message.data as CallInvite;\n const held = incoming.get(invite.id);\n if (held !== undefined) settleLocal(invite);\n },\n },\n ],\n postgresChanges: [\n {\n event: \"INSERT\",\n schema: repository.schema,\n table: repository.tables.invites,\n filter: `callee_ids=cs.{${me}}`,\n rowId: (row) => (typeof row[\"id\"] === \"string\" ? row[\"id\"] : undefined),\n onChange: (delivery) => {\n if (delivery.row === null) return;\n ingest(repository.projectInvite(delivery.row));\n },\n },\n {\n event: \"UPDATE\",\n schema: repository.schema,\n table: repository.tables.invites,\n filter: `callee_ids=cs.{${me}}`,\n rowId: (row) => (typeof row[\"id\"] === \"string\" ? row[\"id\"] : undefined),\n onChange: (delivery) => {\n if (delivery.row === null) return;\n const invite = repository.projectInvite(delivery.row);\n if (invite.state !== \"ringing\" && invite.state !== \"dialing\") {\n const held = incoming.get(invite.id);\n if (held !== undefined) settleLocal(invite);\n }\n },\n },\n ],\n // THE BACKFILL DOOR. Realtime has no replay: a socket that dropped for\n // 20 seconds must re-read, or a call placed during the gap rings on the\n // caller's screen and nowhere else.\n onBackfill: async () => {\n const pending = await repository.pendingInvites(me);\n for (const invite of pending) ingest(invite);\n },\n });\n const pending = await repository.pendingInvites(me);\n for (const invite of pending) ingest(invite);\n },\n\n async call({ people, mode, conversationId }) {\n const me = requireUser(\"meet.calls.call\");\n if (people.length === 0) {\n throw new MeetError(\n \"misconfigured\",\n \"meet.calls.call: no callees\",\n \"Pass at least one user id. An empty call would create a room nobody is invited to.\",\n );\n }\n // The room name is minted CLIENT-SIDE and is opaque: the server validates\n // membership when it mints the token, so a guessed room name buys nothing.\n const roomName: RoomName = asRoomName(\n `call-${me}-${timers.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`,\n );\n const invite = await repository.createCallInvite({\n roomName,\n mode,\n callerUserId: me,\n callerName: identity.displayName,\n callerAvatarUrl: identity.avatarUrl,\n calleeUserIds: people,\n organizationId: identity.organizationId,\n conversationId: conversationId ?? null,\n expiresAt: new Date(timers.now() + ringTimeoutMs).toISOString(),\n });\n outgoing = invite;\n\n // The instant leg. The durable leg already happened — the row is written.\n for (const callee of people) {\n to(callee).send(MEET_EVENTS.ring, invite);\n }\n timeouts.set(\n invite.id,\n timers.setTimeout(() => {\n if (outgoing?.id !== invite.id) return;\n void repository\n .settleCallInvite(invite.id, \"missed\", null)\n .then((settled) => {\n outgoing = settled;\n options.onSettled?.(settled);\n })\n .catch(() => undefined);\n }, ringTimeoutMs),\n );\n return invite;\n },\n\n async accept(id, mode) {\n const held = incoming.get(id);\n if (held !== undefined && !canTransition(held.state, \"connecting\")) {\n throw new MeetError(\n \"conflict\",\n `meet.calls.accept: this call is already ${held.state}`,\n \"A late accept must not resurrect a settled call. Close the ringing UI; the caller \" +\n \"has already moved on.\",\n );\n }\n const settled = await repository.settleCallInvite(id, \"connecting\", null);\n settleLocal(settled);\n // Tell my OTHER devices to stop ringing, and the caller to stop waiting.\n channel?.send(MEET_EVENTS.settled, settled);\n to(settled.callerUserId).send(MEET_EVENTS.settled, { ...settled, mode });\n return settled;\n },\n\n async decline(id, message) {\n const settled = await repository.settleCallInvite(id, \"declined\", message ?? null);\n settleLocal(settled);\n channel?.send(MEET_EVENTS.settled, settled);\n to(settled.callerUserId).send(MEET_EVENTS.settled, settled);\n return settled;\n },\n\n async cancel(id) {\n const settled = await repository.settleCallInvite(id, \"cancelled\", null);\n clearRing(id);\n if (outgoing?.id === id) outgoing = settled;\n for (const callee of settled.calleeUserIds) {\n to(callee).send(MEET_EVENTS.cancel, settled);\n }\n return settled;\n },\n\n incoming: () => [...incoming.values()],\n outgoing: () => outgoing,\n ingest,\n\n dispose() {\n for (const id of [...timeouts.keys()]) clearRing(asCallId(id));\n incoming.clear();\n for (const handle of outbound.values()) handle.close();\n outbound.clear();\n channel?.close();\n channel = null;\n },\n };\n}\n","/**\n * DEVICE MANAGEMENT — the part users blame the product for.\n *\n * Every rule here exists because it is a support ticket somewhere:\n *\n * - **Labels are empty until permission is granted.** `enumerateDevices()`\n * happily returns three cameras with blank labels before the prompt. A picker\n * rendering \"Camera 1 / Camera 2\" is the classic symptom; we report\n * `labelsHidden` so the UI can say *why* instead.\n * - **A remembered device can vanish.** Unplug a headset between meetings and a\n * stored `deviceId` produces `OverconstrainedError`. The manager falls back to\n * the system default AND SAYS SO — a silent fallback is how someone joins on\n * the laptop mic while believing they are on their headset.\n * - **Selections persist per KIND, per device.** Injected storage (C10:\n * persistence-injected — this package's core purpose is not storage), with a\n * memory fallback that announces itself rather than pretending to be durable.\n * - **Enumeration is repeated on `devicechange`.** A picker that lists what was\n * plugged in at mount is wrong within seconds of a headset arriving.\n */\n\nimport { MeetError, normalizeDeviceError } from \"./errors\";\n\nexport type DeviceKind = \"audioinput\" | \"videoinput\" | \"audiooutput\";\n\nexport interface MeetDevice {\n readonly deviceId: string;\n readonly kind: DeviceKind;\n readonly label: string;\n}\n\nexport interface DeviceSnapshot {\n readonly devices: Readonly<Record<DeviceKind, readonly MeetDevice[]>>;\n readonly selected: Readonly<Record<DeviceKind, string | null>>;\n /** True when the browser is hiding labels because permission was not granted. */\n readonly labelsHidden: boolean;\n readonly permission: \"unknown\" | \"granted\" | \"denied\";\n /** Set when a remembered device was gone and we fell back. Shown, not swallowed. */\n readonly fallbackNotice: string | null;\n}\n\nexport interface DeviceStorage {\n read(): Record<string, string>;\n write(value: Record<string, string>): void;\n readonly durable: boolean;\n}\n\nexport interface MediaDevicesLike {\n enumerateDevices(): Promise<\n readonly { deviceId: string; kind: string; label: string }[]\n >;\n getUserMedia(constraints: { audio?: unknown; video?: unknown }): Promise<{\n getTracks(): readonly { stop(): void }[];\n }>;\n addEventListener?: ((type: \"devicechange\", handler: () => void) => void) | undefined;\n removeEventListener?: ((type: \"devicechange\", handler: () => void) => void) | undefined;\n}\n\nexport interface DeviceManagerOptions {\n media: MediaDevicesLike;\n storage?: DeviceStorage | undefined;\n onChange?: ((snapshot: DeviceSnapshot) => void) | undefined;\n}\n\nexport interface DeviceManager {\n /**\n * 🚨 THE SAME REFERENCE until something actually changes. This is a\n * `useSyncExternalStore` `getSnapshot` source (see `useDeviceSnapshot`), and\n * React compares snapshots by IDENTITY: a fresh object literal per call makes\n * every render report a change, which React reports as *\"The result of\n * getSnapshot should be cached\"* and then kills the tree with *\"Maximum\n * update depth exceeded\"*. `createMeetStore()` has always held this contract;\n * 0.2.0 shipped without it here and every room crashed at `<PreJoin>`.\n */\n snapshot(): DeviceSnapshot;\n /** Enumerate without prompting. Labels may be hidden; that is reported. */\n refresh(): Promise<DeviceSnapshot>;\n /** Prompt, then enumerate with real labels. The pre-join screen calls this. */\n requestPermission(kinds: { audio: boolean; video: boolean }): Promise<DeviceSnapshot>;\n select(kind: DeviceKind, deviceId: string): DeviceSnapshot;\n /** The id to actually use — the remembered one, or the default when it is gone. */\n resolve(kind: DeviceKind): string | null;\n subscribe(listener: (snapshot: DeviceSnapshot) => void): () => void;\n dispose(): void;\n}\n\nconst KINDS: readonly DeviceKind[] = [\"audioinput\", \"videoinput\", \"audiooutput\"];\n\nfunction isDeviceKind(value: string): value is DeviceKind {\n return value === \"audioinput\" || value === \"videoinput\" || value === \"audiooutput\";\n}\n\n/** localStorage when it exists; memory otherwise — and it says which. */\nexport function createWebDeviceStorage(key = \"mx.meet.devices\"): DeviceStorage {\n const store = (globalThis as { localStorage?: Storage }).localStorage;\n if (store === undefined) return createMemoryDeviceStorage();\n return {\n durable: true,\n read() {\n try {\n const raw = store.getItem(key);\n if (raw === null) return {};\n const parsed: unknown = JSON.parse(raw);\n return typeof parsed === \"object\" && parsed !== null\n ? (parsed as Record<string, string>)\n : {};\n } catch {\n return {};\n }\n },\n write(value) {\n try {\n store.setItem(key, JSON.stringify(value));\n } catch {\n // A full or blocked storage must not break joining a call.\n }\n },\n };\n}\n\nexport function createMemoryDeviceStorage(): DeviceStorage {\n let value: Record<string, string> = {};\n return {\n durable: false,\n read: () => value,\n write: (next) => {\n value = next;\n },\n };\n}\n\nexport function createDeviceManager(options: DeviceManagerOptions): DeviceManager {\n const storage = options.storage ?? createMemoryDeviceStorage();\n const listeners = new Set<(snapshot: DeviceSnapshot) => void>();\n const stored = storage.read();\n\n let devices: Record<DeviceKind, readonly MeetDevice[]> = {\n audioinput: [],\n videoinput: [],\n audiooutput: [],\n };\n let selected: Record<DeviceKind, string | null> = {\n audioinput: stored[\"audioinput\"] ?? null,\n videoinput: stored[\"videoinput\"] ?? null,\n audiooutput: stored[\"audiooutput\"] ?? null,\n };\n let labelsHidden = true;\n let permission: DeviceSnapshot[\"permission\"] = \"unknown\";\n let fallbackNotice: string | null = null;\n\n // 🚨 THE MEMOIZED SNAPSHOT. `current` IS the snapshot; readers get this exact\n // object until `commit()` replaces it, which happens only when one of the\n // five fields above actually moved. See the `DeviceManager.snapshot` doc\n // comment for the crash this prevents.\n let current: DeviceSnapshot = {\n devices,\n selected,\n labelsHidden,\n permission,\n fallbackNotice,\n };\n\n function snapshot(): DeviceSnapshot {\n return current;\n }\n\n /** Rebuild the snapshot from the current state. Call after ANY mutation. */\n function commit(): DeviceSnapshot {\n current = { devices, selected, labelsHidden, permission, fallbackNotice };\n return current;\n }\n\n function emit(): DeviceSnapshot {\n const next = commit();\n options.onChange?.(next);\n for (const listener of listeners) listener(next);\n return next;\n }\n\n async function enumerate(): Promise<DeviceSnapshot> {\n let raw: readonly { deviceId: string; kind: string; label: string }[];\n try {\n raw = await options.media.enumerateDevices();\n } catch (error) {\n throw normalizeDeviceError(error, \"meet.enumerateDevices\");\n }\n const grouped: Record<DeviceKind, MeetDevice[]> = {\n audioinput: [],\n videoinput: [],\n audiooutput: [],\n };\n let anyLabel = false;\n for (const device of raw) {\n if (!isDeviceKind(device.kind)) continue;\n if (device.label.length > 0) anyLabel = true;\n grouped[device.kind].push({\n deviceId: device.deviceId,\n kind: device.kind,\n label: device.label,\n });\n }\n devices = grouped;\n labelsHidden = !anyLabel && raw.length > 0;\n\n // THE VANISHED-DEVICE FALLBACK. A remembered id that is no longer present\n // is dropped to the system default, and the notice is part of the snapshot\n // so the UI can say \"your headset is unplugged — using the built-in mic\".\n const lost: string[] = [];\n for (const kind of KINDS) {\n const current = selected[kind];\n if (current === null) continue;\n if (!grouped[kind].some((device) => device.deviceId === current)) {\n selected = { ...selected, [kind]: null };\n lost.push(kind);\n }\n }\n fallbackNotice =\n lost.length === 0\n ? null\n : `A remembered ${lost.join(\" and \")} device is no longer connected — using the ` +\n \"system default. Pick another in the device menu.\";\n return emit();\n }\n\n const onDeviceChange = (): void => {\n void enumerate();\n };\n options.media.addEventListener?.(\"devicechange\", onDeviceChange);\n\n return {\n snapshot,\n refresh: enumerate,\n async requestPermission(kinds) {\n if (!kinds.audio && !kinds.video) {\n throw new MeetError(\n \"misconfigured\",\n \"meet.requestPermission: asked for neither audio nor video\",\n \"Request at least one kind. Prompting for nothing silently resolves and leaves \" +\n \"labels hidden, which looks like a broken picker.\",\n );\n }\n try {\n const stream = await options.media.getUserMedia({\n ...(kinds.audio ? { audio: true } : {}),\n ...(kinds.video ? { video: true } : {}),\n });\n // 🚨 STOP THE PROBE STREAM. Holding it keeps the camera light on and,\n // on Windows, makes the real join fail with NotReadableError — the\n // device is busy with our own probe.\n for (const track of stream.getTracks()) track.stop();\n permission = \"granted\";\n } catch (error) {\n permission = \"denied\";\n emit();\n throw normalizeDeviceError(error, \"meet.requestPermission\");\n }\n return enumerate();\n },\n select(kind, deviceId) {\n selected = { ...selected, [kind]: deviceId };\n fallbackNotice = null;\n storage.write({\n ...storage.read(),\n [kind]: deviceId,\n });\n return emit();\n },\n resolve(kind) {\n const current = selected[kind];\n if (current !== null && devices[kind].some((device) => device.deviceId === current)) {\n return current;\n }\n return devices[kind][0]?.deviceId ?? null;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n dispose() {\n options.media.removeEventListener?.(\"devicechange\", onDeviceChange);\n listeners.clear();\n },\n };\n}\n","/**\n * WHO SAID THAT — one answer, every surface, both lanes (MRI-A16).\n *\n * 🚨 **A RAW LIVEKIT IDENTITY IS NEVER A PERSON'S NAME.** On production\n * 2026-09-09 the host's caption rail read *\"Ada Lovelace: I planted a marigold\n * in the courtyard\"* and the guest's — the same meeting, the same second —\n * read *\"guest:c8-spk-1\"*, because the host resolved the name from the durable\n * rows it can read and the guest had no fallback at all and printed the token\n * (MRI-C8). Two surfaces disagreeing about who is speaking is worse than either\n * one being ugly: a person reading the transcript cannot tell whether those are\n * one speaker or two.\n *\n * The cure is that nothing resolves a name for itself. Every source that\n * happens to KNOW a name teaches this book — the LiveKit roster, a durable\n * `meet_transcript_segments` row, a durable `meet_participants` row, a chat\n * message, our own identity — and every surface asks it. Three rules:\n *\n * 1. **A name is learned, never unlearned.** Someone who leaves the room keeps\n * the name they had; a caption that lands after them still says who spoke.\n * This is the \"last known name\" rule, and it is why the book is a store\n * field rather than a derivation over the current roster.\n * 2. **An identity is not a name.** `learn` refuses a \"name\" that is the\n * identity itself — which is exactly what the LiveKit roster hands back for\n * a participant whose token carried no name, and exactly how the token got\n * onto the screen in the first place.\n * 3. **When nobody knows, SAY nobody knows.** `displayNameFor` answers with an\n * honest placeholder — \"Unnamed guest\" / \"Unnamed participant\" — never a\n * token, and never an invented name. The placeholder is deliberately not\n * unique, so surfaces that must keep two unnamed people apart group by\n * IDENTITY rather than by the rendered name.\n */\n\nimport type { ParticipantIdentity } from \"./types\";\n\n/** Identity → the best display name anything has ever known for it. */\nexport type NameBook = Readonly<Record<string, string>>;\n\n/** A guest's identity is minted `guest:<something>` by the token route. */\nexport function isGuestIdentity(identity: ParticipantIdentity | string): boolean {\n return String(identity).startsWith(\"guest:\");\n}\n\n/**\n * An AGENT's identity is minted `agent:<capability>:<meeting>` by the server\n * (`services/meet/worker.py`). An agent is never an anonymous \"participant\":\n * it is a product with a name, and a room that cannot say which product is\n * listening has failed the consent notice it is required to carry (D10).\n */\nexport function isAgentIdentity(identity: ParticipantIdentity | string): boolean {\n return String(identity).startsWith(\"agent:\");\n}\n\n/** The note-taker's product name — `services/meet/worker.py::AGENT_DISPLAY_NAME`. */\nexport const NOTE_TAKER_PRODUCT_NAME = \"Matrx note-taker\";\n/** Any other Matrx agent whose dispatch carried no name. */\nexport const AGENT_PRODUCT_NAME = \"Matrx agent\";\n/** Somebody in the room whose name nothing has ever known. */\nexport const UNNAMED_GUEST = \"Unnamed guest\";\n/** The same, for a participant whose identity is not a guest token. */\nexport const UNNAMED_PARTICIPANT = \"Unnamed participant\";\n\n/**\n * The strings THIS MODULE invents when nobody knows a name. They are answers,\n * never facts: `isRealName` refuses them, so a placeholder can never be learned\n * as somebody's name and can never outrank a real name that arrives later.\n *\n * 🚨 This is what makes the roster safe to route through the book. A roster\n * event projects \"Unnamed guest\" for a nameless participant; a durable\n * transcript row then teaches \"Ada Lovelace\"; without this rule the placeholder\n * — a perfectly ordinary-looking string — would win, and the screen would keep\n * saying \"Unnamed guest\" about somebody the meeting plainly knows.\n */\nconst PLACEHOLDER_NAMES: readonly string[] = [\n NOTE_TAKER_PRODUCT_NAME,\n AGENT_PRODUCT_NAME,\n UNNAMED_GUEST,\n UNNAMED_PARTICIPANT,\n];\n\n/** Is this string one of the placeholders this module produces? */\nexport function isPlaceholderName(name: string | null | undefined): boolean {\n return typeof name === \"string\" && PLACEHOLDER_NAMES.includes(name.trim());\n}\n\n/** What an identity is called when NOTHING knows a name for it. Never a token. */\nexport function placeholderNameFor(identity: ParticipantIdentity | string): string {\n const key = String(identity);\n if (isAgentIdentity(key)) {\n return key.startsWith(\"agent:note_taker:\") || key.startsWith(\"agent:note-taker\")\n ? NOTE_TAKER_PRODUCT_NAME\n : AGENT_PRODUCT_NAME;\n }\n return isGuestIdentity(key) ? UNNAMED_GUEST : UNNAMED_PARTICIPANT;\n}\n\n/**\n * Would this string be a real name for this identity? A name equal to the\n * identity is the roster's way of saying it has none.\n */\nexport function isRealName(\n identity: ParticipantIdentity | string,\n name: string | null | undefined,\n): boolean {\n if (typeof name !== \"string\") return false;\n const trimmed = name.trim();\n if (trimmed.length === 0) return false;\n if (trimmed === String(identity)) return false;\n // Our own answer is not new information. See PLACEHOLDER_NAMES.\n if (isPlaceholderName(trimmed)) return false;\n return true;\n}\n\n/**\n * Teach the book one identity's name. Returns the SAME book when nothing was\n * learned, so a store commit can be skipped rather than waking every subscriber\n * on every caption.\n */\nexport function learnName(\n book: NameBook,\n identity: ParticipantIdentity | string,\n name: string | null | undefined,\n): NameBook {\n const key = String(identity);\n if (key.length === 0) return book;\n if (!isRealName(key, name)) return book;\n const learned = (name as string).trim();\n if (book[key] === learned) return book;\n return { ...book, [key]: learned };\n}\n\n/** Teach the book several at once — a roster replace, or a durable read. */\nexport function learnNames(\n book: NameBook,\n entries: readonly {\n identity: ParticipantIdentity | string;\n displayName?: string | null | undefined;\n }[],\n): NameBook {\n let next = book;\n for (const entry of entries) next = learnName(next, entry.identity, entry.displayName);\n return next;\n}\n\n/**\n * The name a surface renders for `identity`. Never a raw token, never invented.\n *\n * `preferred` is what the arriving thing itself claimed (a caption's roster\n * lookup, a durable row's `speaker` column); it wins when it is a real name,\n * because it is the freshest, and teaches the book on its way past.\n */\nexport function displayNameFor(\n book: NameBook,\n identity: ParticipantIdentity | string,\n preferred?: string | null | undefined,\n): string {\n const key = String(identity);\n if (isRealName(key, preferred)) return (preferred as string).trim();\n const known = book[key];\n if (known !== undefined) return known;\n // NOBODY KNOWS, AND THAT IS WHAT IT SAYS. A person reading this can tell the\n // difference between \"someone whose name we never learned\" and a name.\n return placeholderNameFor(key);\n}\n","/**\n * RECORDING — LiveKit Egress, host-controlled, consent-enforced (R3/R5).\n *\n * 🚨 **CONSENT IS NOT OPTIONAL AND NOT A PROP.** There is no\n * `showRecordingIndicator={false}`. Recording a person without telling them is\n * illegal in a two-party-consent jurisdiction and is indefensible everywhere\n * else, so the indicator and the join-time notice are properties of the\n * package, not decisions a consumer gets to make. The only knob is the org's\n * `recordingPolicy` — disabled / host-controlled / always-on — which decides\n * whether recording may happen at all, never whether people are told.\n *\n * 🚨 **THE RECORDING BELONGS TO THE PLATFORM, NOT TO LIVEKIT.** The server\n * lands the artifact in the platform files system and returns a FILE ID. A\n * provider URL would be an orphan the day the room is garbage collected — the\n * reason `RecordingRecord.fileId` is not `url`.\n *\n * The client half is small on purpose: start/stop are aidream calls (the API\n * secret never comes near a browser), and the truth about a recording arrives\n * from the server's webhook through the room channel. This module never\n * *guesses* that a recording started.\n */\n\nimport type { MeetApi } from \"./api\";\nimport { MeetError } from \"./errors\";\nimport type { MeetStore } from \"./store\";\nimport { MEET_ROUTES } from \"./tokens\";\nimport type {\n MeetingId,\n MeetingRecord,\n RecordingState,\n RoomName,\n UserId,\n} from \"./types\";\n\nexport interface RecordingControllerOptions {\n /** The ONE org-aware aidream client (MRI-A16). Owns base url and headers. */\n api: MeetApi;\n store: MeetStore;\n /** Announce the new state to everyone in the room (the indicator is for all). */\n announce?: ((state: RecordingState, by: UserId | null) => void) | undefined;\n /** Persist that this participant saw the notice. Consent is RECORDED (R5). */\n acknowledgeConsent?: ((meetingId: MeetingId) => Promise<void>) | undefined;\n}\n\nexport interface RecordingController {\n /** True when the org policy and the actor's role allow starting a recording. */\n canStart(meeting: MeetingRecord | null, isHost: boolean): boolean;\n start(args: { meetingId: MeetingId; roomName: RoomName; by: UserId }): Promise<void>;\n stop(args: { meetingId: MeetingId; by: UserId }): Promise<void>;\n /** The join-time notice text. One sentence, one place, every surface. */\n consentNotice(meeting: MeetingRecord | null): string | null;\n acknowledge(meetingId: MeetingId): Promise<void>;\n}\n\nexport function createRecordingController(\n options: RecordingControllerOptions,\n): RecordingController {\n async function post(route: string, body: Record<string, unknown>): Promise<void> {\n let response: Response;\n try {\n response = await options.api.request({\n path: route,\n method: \"POST\",\n // A GUEST CAN NEVER START OR STOP A RECORDING (R5) — refused here,\n // before the wire, with the same sentence the hidden control implies.\n requireAuth: true,\n operation: \"meet.recording\",\n body,\n });\n } catch (error) {\n if ((error as { code?: string }).code === \"session-unavailable\") {\n throw new MeetError(\n \"forbidden\",\n \"meet.recording: recording requires an authenticated host\",\n \"A guest can never start or stop a recording (R5). The control is hidden for guests.\",\n );\n }\n throw error;\n }\n if (response.status === 403) {\n throw new MeetError(\n \"forbidden\",\n \"meet.recording: the server refused this recording action\",\n \"The actor is not a host of this meeting, or the org policy is `disabled`. The server \" +\n \"is the authority; do not re-decide it on the client.\",\n );\n }\n if (!response.ok) {\n throw new MeetError(\n \"transport\",\n `meet.recording: the server returned ${response.status}`,\n \"Egress could not be controlled. The recording state stays where it was rather than \" +\n \"showing a recording indicator for a recording that is not running.\",\n );\n }\n }\n\n return {\n canStart(meeting, isHost) {\n if (meeting === null) return false;\n if (meeting.recordingPolicy === \"disabled\") return false;\n // `always-on` is started by the SERVER when the room opens; a host cannot\n // start (or stop) it, which is the point of the policy.\n if (meeting.recordingPolicy === \"always-on\") return false;\n return isHost;\n },\n\n async start({ meetingId, roomName, by }) {\n // OPTIMISTIC ONLY AS FAR AS \"starting\", and marked `\"local\"` so the\n // durable row overrules it the moment it lands (D16). The indicator turns\n // solid when the SERVER says the egress is running — never on a client's\n // hope, and never STUCK on that hope either: `meet_recordings` is\n // subscribed and `matrx.meet.recording` reaches the guests (MRI-A16).\n options.store.setRecording(\"starting\", by, \"local\");\n try {\n await post(MEET_ROUTES.recordingStart, {\n meeting_id: meetingId,\n room_name: roomName,\n });\n } catch (error) {\n options.store.setRecording(\"idle\", null, \"local\");\n throw error;\n }\n options.announce?.(\"starting\", by);\n },\n\n async stop({ meetingId, by }) {\n options.store.setRecording(\"stopping\", options.store.snapshot().recordingStartedBy, \"local\");\n try {\n await post(MEET_ROUTES.recordingStop, { meeting_id: meetingId });\n } catch (error) {\n options.store.setRecording(\n \"recording\",\n options.store.snapshot().recordingStartedBy,\n \"local\",\n );\n throw error;\n }\n options.announce?.(\"stopping\", by);\n },\n\n consentNotice(meeting) {\n if (meeting === null || meeting.recordingPolicy === \"disabled\") return null;\n if (meeting.recordingPolicy === \"always-on\") {\n return \"This meeting is recorded and transcribed automatically. By joining, you consent to being recorded.\";\n }\n return \"The host can record and transcribe this meeting. You will see a recording indicator whenever it is running.\";\n },\n\n async acknowledge(meetingId) {\n await options.acknowledgeConsent?.(meetingId);\n },\n };\n}\n\n/**\n * 🚨 IS A RECORDING IN FLIGHT RIGHT NOW? One definition (MRI-A16).\n *\n * The control used to ask `state === \"idle\"`, which was survivable only while\n * the store never learned any state but its own: the moment the DURABLE states\n * started arriving, a meeting whose first recording had finished sat on\n * `available` forever and the host could never start a second one — the Start\n * button simply stopped existing. `processing`, `available` and `failed` all\n * mean \"nothing is recording\"; only these three mean it is.\n */\nexport const RECORDING_IN_FLIGHT: readonly RecordingState[] = [\n \"starting\",\n \"recording\",\n \"stopping\",\n];\n\nexport function isRecordingInFlight(state: RecordingState): boolean {\n return RECORDING_IN_FLIGHT.includes(state);\n}\n\n/** The indicator's words. One definition, so no surface invents a softer one. */\nexport function recordingLabel(state: RecordingState): string | null {\n switch (state) {\n case \"starting\":\n return \"Starting recording…\";\n case \"recording\":\n return \"Recording\";\n case \"stopping\":\n return \"Stopping recording…\";\n case \"processing\":\n return \"Processing recording…\";\n case \"available\":\n return \"Recording ready\";\n case \"expired\":\n return \"Recording expired\";\n case \"failed\":\n return \"Recording failed\";\n default:\n return null;\n }\n}\n","/**\n * LISTEN-ONLY ATTENDANCE — being IN the room is never contingent on a device.\n *\n * 0.3.1 and every version before it enabled the microphone as the last step of\n * `connect()`, inside the same `try` as the join. So a denied, absent, or busy\n * microphone did not produce a muted participant — it threw, the join was\n * failed with a device remedy, and the user was dropped back to `<PreJoin>`\n * having never entered the meeting. The whole in-room surface (tiles, captions,\n * live notes, Q&A, the note-taker consent notice) was unreachable to anyone\n * without a working mic, which is ordinary: a locked-down laptop, a conference\n * room dial-in, a phone on a call, a browser profile that denies capture by\n * policy, or a person who simply wants to listen. Every competitor allows it.\n *\n * THE CLASS, and how it is closed here:\n *\n * 1. **Connecting and publishing are two different operations.** The engine\n * reaches `connected` the moment the transport is up. Media is attempted\n * AFTER that, per track, and a rejection never unwinds the join.\n * 2. **A track that could not be acquired is STATE, not an exception.** The\n * reason and its remedy — the browser's own, translated by\n * `normalizeDeviceError` — ride in the snapshot so the UI says WHY the mic\n * is off instead of showing a mute button that silently does nothing.\n * 3. **Enabling later runs the SAME code path.** `setMicrophoneEnabled(true)`\n * from the control bar records exactly what the join attempt records, so a\n * person who plugs in a headset mid-meeting is one click from speaking and\n * a person whose second attempt also fails gets the same honest sentence.\n * A separate \"retry\" path is how the two drift.\n * 4. **The notice is one sentence, defined once.** Both the package's own room\n * chrome and any host that renders its own read `listenOnlyNotice()`, so\n * there is no second wording to keep in sync.\n */\n\nimport type { MeetError } from \"./errors\";\n\n/** Why a local track is not publishing, in the browser's terms plus a remedy. */\nexport interface MediaUnavailable {\n readonly code: string;\n readonly message: string;\n readonly remedy: string;\n}\n\nexport interface LocalTrackState {\n /** True only when the track is actually published. Never optimistic. */\n readonly enabled: boolean;\n /**\n * Set when acquisition was ATTEMPTED and refused. `null` covers both \"on\"\n * and \"deliberately off\" — a user who unchecked the mic in pre-join is not\n * looking at an error, they are looking at a choice they made.\n */\n readonly unavailable: MediaUnavailable | null;\n}\n\nexport interface LocalMediaState {\n readonly microphone: LocalTrackState;\n readonly camera: LocalTrackState;\n}\n\nexport const IDLE_TRACK: LocalTrackState = { enabled: false, unavailable: null };\n\nexport const IDLE_MEDIA: LocalMediaState = {\n microphone: IDLE_TRACK,\n camera: IDLE_TRACK,\n};\n\nexport function unavailableFrom(error: MeetError): MediaUnavailable {\n return { code: error.code, message: error.message, remedy: error.remedy };\n}\n\n/**\n * THE SENTENCE. One definition, so the room chrome, a host's own chrome and the\n * tests cannot say three different things about the same fact.\n */\nexport const LISTEN_ONLY_NOTICE =\n \"You're attending without a microphone — others can't hear you\";\n\n/**\n * True when this participant is in the room and publishing no microphone —\n * whether the device was refused or simply turned off. Both are listen-only,\n * and both deserve the same honest line; only the REMEDY differs, and that\n * comes from `media.microphone.unavailable`.\n */\nexport function isListenOnly(media: LocalMediaState): boolean {\n return !media.microphone.enabled;\n}\n\n/**\n * The notice to render while in the room, or `null` when the mic is live.\n * Returns the plain sentence; the reason and remedy, when there is one, are\n * rendered beside it from `media.microphone.unavailable`.\n */\nexport function listenOnlyNotice(media: LocalMediaState): string | null {\n return isListenOnly(media) ? LISTEN_ONLY_NOTICE : null;\n}\n","/**\n * CAPTIONS ARE HINTS; SEGMENTS ARE TRUTH (D16).\n *\n * Two independent streams describe the same speech and they arrive out of order\n * with different identities:\n *\n * 1. **Captions** ride the LiveKit `lk.transcription` text stream, keyed by\n * `lk.segment_id`, interim-then-final, milliseconds behind the voice. They\n * exist so a person can READ the room live. Their `sender_identity` is\n * supplied by the publishing client and LiveKit does not validate it, so\n * nothing downstream — notes, Q&A, the wrap-up — may ever read them.\n * 2. **Records** are `communication.meet_transcript_segments` rows, written\n * server-side by the note-taker with a deterministic id (D6) and delivered\n * here by Postgres Changes. They are the meeting's transcript.\n *\n * The reconciliation below is what keeps the screen from saying everything\n * twice. A record REPLACES the caption it supersedes — matched by the caption\n * id the worker carries into the row, and failing that by speaker + text — and\n * a caption never overwrites a record, however late it lands.\n *\n * Everything here is a pure function over a list so the rules are provable\n * without a store, a socket, or a browser.\n */\n\nimport type { ParticipantIdentity, TranscriptSegment } from \"./types\";\n\n/** Comparable text: case, punctuation and spacing are not differences. */\nexport function normalizeSpoken(text: string): string {\n return text\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}]+/gu, \" \")\n .trim();\n}\n\nfunction supersedes(record: TranscriptSegment, caption: TranscriptSegment): boolean {\n if (caption.source !== \"caption\") return false;\n if (caption.identity !== record.identity) return false;\n if (record.captionId !== null && caption.captionId === record.captionId) return true;\n const left = normalizeSpoken(record.text);\n const right = normalizeSpoken(caption.text);\n if (left.length === 0 || right.length === 0) return false;\n // An interim caption is a PREFIX of what was finally said; a final caption and\n // its record usually differ only in punctuation. Both are the same utterance.\n return left === right || left.startsWith(right) || right.startsWith(left);\n}\n\n/**\n * A caption arrived. Interim replaces interim in place; a final never loses to a\n * late interim; a record is never touched.\n */\nexport function mergeCaption(\n list: readonly TranscriptSegment[],\n caption: TranscriptSegment,\n): readonly TranscriptSegment[] {\n const index = list.findIndex(\n (entry) => entry.captionId !== null && entry.captionId === caption.captionId,\n );\n if (index === -1) {\n // The record for this utterance may already be here (the row can beat the\n // caption on a slow media path). Do not draw the same sentence twice.\n if (list.some((entry) => entry.source === \"record\" && supersedes(entry, caption))) {\n return list;\n }\n return [...list, caption];\n }\n const existing = list[index];\n if (existing === undefined) return list;\n // TRUTH WINS. A caption cannot revert a durable row, and a late interim cannot\n // revert a final — that is a finished sentence visibly becoming a half-word.\n if (existing.source === \"record\") return list;\n if (existing.final && !caption.final) return list;\n return list.map((entry, position) => (position === index ? caption : entry));\n}\n\n/**\n * A durable row arrived. It replaces the caption it supersedes — in place, so\n * the line does not jump down the panel — or lands as a new line if no caption\n * ever showed it (a surface that joined late, or captions that never came).\n */\nexport function mergeRecord(\n list: readonly TranscriptSegment[],\n record: TranscriptSegment,\n): readonly TranscriptSegment[] {\n const byId = list.findIndex((entry) => entry.source === \"record\" && entry.id === record.id);\n if (byId !== -1) {\n const existing = list[byId];\n if (existing !== undefined && existing.text === record.text && existing.final === record.final) {\n return list;\n }\n return list.map((entry, position) => (position === byId ? record : entry));\n }\n const captionIndex = list.findIndex((entry) => supersedes(record, entry));\n if (captionIndex === -1) return [...list, record];\n return list.map((entry, position) => (position === captionIndex ? record : entry));\n}\n\n/** The transcript a person reads: chronological, and never an empty line. */\nexport function readableTranscript(\n list: readonly TranscriptSegment[],\n): readonly TranscriptSegment[] {\n return [...list]\n .filter((entry) => entry.text.trim().length > 0)\n .sort((left, right) => left.startedAt.localeCompare(right.startedAt));\n}\n\n/** Build a caption line from the media plane. */\nexport function captionSegment(args: {\n captionId: string;\n meetingId: TranscriptSegment[\"meetingId\"];\n identity: ParticipantIdentity;\n speaker: string;\n text: string;\n final: boolean;\n startedAt: string;\n}): TranscriptSegment {\n return {\n id: `caption:${args.captionId}`,\n meetingId: args.meetingId,\n identity: args.identity,\n speaker: args.speaker,\n text: args.text,\n startedAt: args.startedAt,\n final: args.final,\n source: \"caption\",\n captionId: args.captionId,\n };\n}\n","/**\n * THE ROOM SNAPSHOT — one immutable object the UI renders and nothing else.\n *\n * Deliberately NOT Redux, NOT a context full of `useState`, and NOT a bag of\n * refs: one store with `getSnapshot`/`subscribe` is exactly what\n * `useSyncExternalStore` wants, which is what makes tearing impossible when a\n * roster event and a speaker event land in the same tick.\n *\n * The rules encoded here:\n *\n * - **The roster is replaced wholesale, never patched.** The driver hands us\n * the full truth on every media event (see `room-driver.ts`); merging deltas\n * from six event sources is how a tile for someone who left stays on screen.\n * - **Ephemera EXPIRE.** Reactions and speaking flags are time-boxed in the\n * snapshot, so a dropped \"stop\" event cannot leave a permanent 🎉 or a\n * permanently-speaking ring. (Nothing here relies on receiving an end event.)\n * - **An interim transcript line is REPLACED in place by its final.** Appending\n * both is how a transcript ends up saying everything twice.\n */\n\nimport { displayNameFor, learnName, learnNames, type NameBook } from \"./names\";\nimport { isRecordingInFlight } from \"./recording\";\nimport { IDLE_MEDIA, type LocalMediaState, type LocalTrackState } from \"./attendance\";\nimport { ROLE_RANK } from \"./types\";\nimport type { NoteTakerRefusal } from \"./note-taker\";\nimport { mergeCaption, mergeRecord } from \"./transcript\";\nimport type {\n AdmissionState,\n ConnectionQuality,\n LobbyEntry,\n MeetParticipant,\n MeetingNote,\n MeetingRecord,\n ParticipantIdentity,\n ParticipantRole,\n RecordingSource,\n RecordingState,\n RoomPhase,\n StageLayout,\n TranscriptSegment,\n UserId,\n WrapUpAnnouncement,\n} from \"./types\";\n\nexport interface RoomChatMessage {\n readonly id: string;\n readonly identity: ParticipantIdentity;\n readonly displayName: string;\n readonly text: string;\n readonly at: string;\n /**\n * Set for a PRIVATE message: the one identity it was addressed to (from the\n * sender's side) or this participant (from the receiver's). Private messages\n * travel the data plane only and are never saved (Meet wave 2).\n */\n readonly to?: ParticipantIdentity | null | undefined;\n /** True once the server has SAVED it — a message everyone sees, late joiners too. */\n readonly saved?: boolean | undefined;\n /** A send the server refused, with its sentence. The message stays visible, marked. */\n readonly failed?: string | undefined;\n}\n\n/**\n * A HOST ACTED ON *ME* (Meet wave 2) — the server's own `matrx.meet.moderation`\n * packet, addressed to this participant. Rendered once, dismissible, in words.\n */\nexport interface ModerationNotice {\n readonly kind: \"muted\" | \"ask-unmute\" | \"removed\" | \"role\";\n readonly text: string;\n readonly at: number;\n}\n\n/** What this participant chose for their own media. Remembered per browser. */\nexport interface MediaEffects {\n readonly noiseSuppression: boolean;\n readonly background: \"none\" | \"blur\" | \"image\";\n readonly backgroundImage: string | null;\n}\n\nexport const DEFAULT_EFFECTS: MediaEffects = {\n noiseSuppression: true,\n background: \"none\",\n backgroundImage: null,\n};\n\nexport interface RoomReaction {\n readonly id: string;\n readonly identity: ParticipantIdentity;\n readonly emoji: string;\n readonly at: number;\n}\n\n/**\n * 🚨 WHAT THE SERVER GRANTED THIS JOINER, straight off the token response\n * (MRI-A11). It is placed in the snapshot the instant the token lands — before\n * the LiveKit roster exists at all — so a host's controls are correct on the\n * first frame of the room rather than one roster event later. The roster entry\n * for the local participant carries the SAME decision as a LiveKit attribute;\n * the two agree because one server statement produced both, and the UI reads\n * whichever has arrived.\n */\nexport interface MeetGrants {\n readonly role: ParticipantRole;\n readonly canRecord: boolean;\n readonly canPublish: boolean;\n readonly canSubscribe: boolean;\n}\n\n/** No token yet grants nothing. Never \"assume host until told otherwise\". */\nexport const NO_GRANTS: MeetGrants = {\n role: \"participant\",\n canRecord: false,\n canPublish: false,\n canSubscribe: false,\n};\n\nexport interface MeetSnapshot {\n readonly phase: RoomPhase;\n readonly meeting: MeetingRecord | null;\n readonly localIdentity: ParticipantIdentity | null;\n /** The server's word on what THIS joiner may do. See `MeetGrants`. */\n readonly grants: MeetGrants;\n readonly participants: readonly MeetParticipant[];\n readonly activeSpeakers: readonly ParticipantIdentity[];\n readonly pinned: ParticipantIdentity | null;\n readonly layout: StageLayout;\n readonly lobby: readonly LobbyEntry[];\n readonly locked: boolean;\n /**\n * 🚨 THE DURABLE `meet_recordings.state`, not a client's hope. Through 0.4.7\n * this only ever held what THIS browser optimistically patched — `starting`\n * on the click, `stopping` on the stop — so the indicator read \"Starting\n * recording…\" for the whole meeting while a perfectly healthy egress ran, and\n * \"Stopping recording…\" forever after (MRI-C8). The server's transitions\n * arrive on two transports now: the `meet_recordings` row for a member, and\n * a `matrx.meet.recording` room event for a guest, who has no database.\n */\n readonly recording: RecordingState;\n readonly recordingStartedBy: UserId | null;\n /**\n * WHICH transport last spoke, so the two cannot undo each other (D16). The\n * database wins: `\"record\"` is never overwritten by `\"room\"` or `\"local\"`.\n */\n readonly recordingSource: RecordingSource;\n /**\n * WHICH recording this state is about. It is what tells a LATE packet for a\n * finished recording apart from the FIRST packet of the next one — without\n * it, \"the database wins\" either blocks a second recording forever or lets a\n * stale packet drag a finished one back to `recording`.\n */\n readonly recordingId: string | null;\n readonly chat: readonly RoomChatMessage[];\n /** Whether the SAVED chat has been read for this meeting (late joiners see history). */\n readonly chatLoaded: boolean;\n /** Why the saved chat could not be read on join, in words — or null. */\n readonly chatHistoryError: string | null;\n readonly reactions: readonly RoomReaction[];\n /**\n * The participant a HOST spotlighted for everyone, from the room's metadata\n * (server-set, delivered on join). A local pin outranks it on this screen only.\n */\n readonly spotlight: ParticipantIdentity | null;\n /** The last thing a host did to THIS participant, in words. Dismissible. */\n readonly moderationNotice: ModerationNotice | null;\n /**\n * The server's answer to the last host action THIS participant took (\"Muted 3\n * people\", or the refusal). One place, so whichever surface acted — a tile's\n * menu, the People panel, More options — the sentence survives the menu closing.\n */\n readonly actionNotice: { readonly text: string; readonly failed: boolean; readonly at: number } | null;\n /**\n * \"Message privately\" asked for from ANY per-person menu — a tile's, the\n * People panel's — and answered by the one `ControlBar` that owns the chat\n * panel (0.7.8). Through 0.7.7 only the People panel could open a private\n * chat, so the Board's tile menu (and the Room's) had no such item while the\n * People panel did: two menus for one person that disagreed.\n */\n readonly privateChatRequest: { readonly to: ParticipantIdentity; readonly at: number } | null;\n readonly effects: MediaEffects;\n /**\n * Captions AND durable rows, reconciled into one list (D16). A record\n * replaces the caption it supersedes; a caption never overwrites a record.\n */\n readonly transcript: readonly TranscriptSegment[];\n readonly notes: readonly MeetingNote[];\n /**\n * 🚨 IDENTITY → THE BEST NAME ANYTHING HAS EVER KNOWN (MRI-A16). Learned from\n * every source that has one — the roster, a durable segment, a durable\n * attendance row, a chat message — and never unlearned, so a caption that\n * lands after somebody leaves still says who spoke. It exists because the\n * host and the guest rendered DIFFERENT names for the same speaker in the\n * same second, one of them a raw LiveKit token (MRI-C8). See `core/names.ts`.\n */\n readonly names: NameBook;\n /**\n * The wrap-up pass ANNOUNCED itself (MRI-A12). `null` means it has not been\n * announced in this room — which is not the same as \"no summary exists\", and\n * no surface may render it as such.\n */\n readonly wrapUp: WrapUpAnnouncement | null;\n /**\n * The server's last refusal to dispatch the note-taker, in ITS words (D7).\n * Rendered verbatim; never replaced by a spinner or a house sentence.\n */\n readonly noteTakerRefusal: NoteTakerRefusal | null;\n /**\n * What the LOCAL participant is actually publishing, and why not when it is\n * not. Attendance never depends on it (see `attendance.ts`): a refused\n * microphone is a state with a remedy, not a failed join.\n */\n readonly media: LocalMediaState;\n /** The last failure, with its remedy. Never null-and-hoping. */\n readonly failure: { readonly message: string; readonly remedy: string } | null;\n}\n\nconst EMPTY: MeetSnapshot = {\n phase: \"idle\",\n meeting: null,\n localIdentity: null,\n grants: NO_GRANTS,\n participants: [],\n activeSpeakers: [],\n pinned: null,\n layout: \"grid\",\n lobby: [],\n locked: false,\n recording: \"idle\",\n recordingStartedBy: null,\n recordingSource: \"local\",\n recordingId: null,\n chat: [],\n chatLoaded: false,\n chatHistoryError: null,\n reactions: [],\n spotlight: null,\n moderationNotice: null,\n actionNotice: null,\n privateChatRequest: null,\n effects: DEFAULT_EFFECTS,\n transcript: [],\n notes: [],\n names: {},\n wrapUp: null,\n noteTakerRefusal: null,\n media: IDLE_MEDIA,\n failure: null,\n};\n\n/**\n * 🚨 THE ONE ANSWER TO \"WHAT ROLE DOES THIS CLIENT'S USER HOLD\" (MRI-A11).\n *\n * Two SERVER-minted carriers, one decision: the `/meet/token` response (in the\n * store from the moment the token lands, before any roster exists) and the\n * local participant's roster entry (whose role comes from the\n * `matrx.participant.role` LiveKit attribute). The stronger wins. Every host\n * power in this package — the UI that renders it AND the code that performs it\n * — asks THIS function, so a control can never render from one source and then\n * be refused by another. That split is exactly how a \"host control\" becomes a\n * button that throws.\n */\nexport function effectiveRole(snapshot: MeetSnapshot): ParticipantRole {\n const me = snapshot.participants.find(\n (participant) => participant.identity === snapshot.localIdentity,\n );\n const fromRoster = me?.role ?? \"participant\";\n const fromToken = snapshot.grants.role;\n return ROLE_RANK[fromRoster] >= ROLE_RANK[fromToken] ? fromRoster : fromToken;\n}\n\n/** Reactions live this long. A dropped end event cannot outlive it. */\nexport const REACTION_TTL_MS = 5_000;\n/** In-room chat is EPHEMERAL by design (R3) — this is the visible backlog. */\nconst CHAT_LIMIT = 200;\n\nexport interface MeetStore {\n snapshot(): MeetSnapshot;\n subscribe(listener: () => void): () => void;\n patch(next: Partial<MeetSnapshot>): void;\n setParticipants(participants: readonly MeetParticipant[]): void;\n setSpeaking(identities: readonly ParticipantIdentity[]): void;\n setQuality(identity: ParticipantIdentity, quality: ConnectionQuality): void;\n /**\n * Raise or lower a hand. `at` is WHEN it went up, which is the hand queue's\n * order — first raised, first called on, the way Meet orders it.\n */\n setHand(identity: ParticipantIdentity, raised: boolean, at?: number): void;\n addChat(message: RoomChatMessage): void;\n /** The saved chat, read once per join. Merged with anything that arrived live. */\n loadChat(messages: readonly RoomChatMessage[]): void;\n /** Replace a pending message (by id) with what the server saved, or mark it failed. */\n settleChat(localId: string, next: RoomChatMessage | { failed: string }): void;\n addReaction(reaction: RoomReaction): void;\n /** Drops reactions past their TTL. Called by the UI's animation frame. */\n expireReactions(now: number): void;\n /**\n * The recording reached a state, and WHO says so. `\"local\"` is this browser's\n * optimistic `starting`/`stopping`; `\"room\"` is the server's packet on the\n * media plane; `\"record\"` is the durable row. Precedence is D16's: the\n * database's word stands until the database changes it.\n */\n setRecording(\n state: RecordingState,\n by: UserId | null,\n source: RecordingSource,\n recordingId?: string | null,\n ): void;\n upsertLobby(entry: LobbyEntry): void;\n setAdmission(identity: ParticipantIdentity, state: AdmissionState, by: UserId | null): void;\n /**\n * Teach the name book. Every source that knows a name calls this, and only\n * a REAL name is learned — an identity handed back as its own name is not one.\n */\n learn(entries: readonly { identity: ParticipantIdentity; displayName?: string | null }[]): void;\n /** A live caption from the media plane. A HINT (D16). */\n ingestCaption(segment: TranscriptSegment): void;\n /** A durable `meet_transcript_segments` row. THE TRANSCRIPT (D16). */\n ingestRecord(segment: TranscriptSegment): void;\n /** Durable notes are re-written in place — a re-run rewrites the same ids. */\n upsertNote(note: MeetingNote): void;\n /** The wrap-up pass finished. Announced on the media plane only (MRI-A12). */\n announceWrapUp(announcement: WrapUpAnnouncement): void;\n /** Record what a local track ACTUALLY did — published, or refused and why. */\n setLocalTrack(kind: \"microphone\" | \"camera\", state: LocalTrackState): void;\n reset(): void;\n}\n\nexport function createMeetStore(initial: Partial<MeetSnapshot> = {}): MeetStore {\n let state: MeetSnapshot = { ...EMPTY, ...initial };\n const listeners = new Set<() => void>();\n\n function commit(next: MeetSnapshot): void {\n if (next === state) return;\n state = next;\n for (const listener of listeners) listener();\n }\n\n return {\n snapshot: () => state,\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n patch(next) {\n commit({ ...state, ...next });\n },\n setParticipants(participants) {\n // The roster TEACHES the book first — a participant whose token carried a\n // real name is where most names come from — and every roster entry is then\n // RESOLVED back through it, so a participant the roster cannot name still\n // gets the best name a durable row or a caption ever taught (MRI-A18).\n const names = learnNames(state.names, participants);\n // Hand-raise state lives on OUR side of the wire (it rides the data\n // plane, not the media plane), so it is carried across a roster replace\n // rather than reset — otherwise every mute event lowers every hand.\n const hands = new Map(state.participants.map((p) => [p.identity, p.handRaised]));\n const handTimes = new Map(state.participants.map((p) => [p.identity, p.handRaisedAt ?? null]));\n const quality = new Map(state.participants.map((p) => [p.identity, p.quality]));\n commit({\n ...state,\n names,\n participants: participants.map((participant) => ({\n ...participant,\n // 🚨 THE ONE ROSTER RESOLUTION. Every surface that renders a person —\n // the tile, the People row, the header summary, every Pin/Mute label —\n // reads `participant.displayName`, so this is the single place a raw\n // identity could reach a screen, and it is the place that asks the\n // name book. `roster-names.test.ts` fails if a token ever gets past it.\n displayName: displayNameFor(names, participant.identity, participant.displayName),\n handRaised: hands.get(participant.identity) ?? participant.handRaised,\n handRaisedAt: handTimes.get(participant.identity) ?? participant.handRaisedAt ?? null,\n quality:\n participant.quality === \"unknown\"\n ? quality.get(participant.identity) ?? \"unknown\"\n : participant.quality,\n })),\n });\n },\n setSpeaking(identities) {\n const speaking = new Set(identities);\n commit({\n ...state,\n activeSpeakers: identities,\n participants: state.participants.map((participant) =>\n participant.speaking === speaking.has(participant.identity)\n ? participant\n : { ...participant, speaking: speaking.has(participant.identity) },\n ),\n });\n },\n setQuality(identity, quality) {\n commit({\n ...state,\n participants: state.participants.map((participant) =>\n participant.identity === identity ? { ...participant, quality } : participant,\n ),\n });\n },\n setHand(identity, raised, at) {\n commit({\n ...state,\n participants: state.participants.map((participant) =>\n participant.identity === identity\n ? {\n ...participant,\n handRaised: raised,\n // A hand that is ALREADY up keeps its place in the queue when\n // it is re-announced (to a late joiner): the first time wins.\n handRaisedAt: raised\n ? participant.handRaised && participant.handRaisedAt != null\n ? participant.handRaisedAt\n : at ?? Date.now()\n : null,\n }\n : participant,\n ),\n });\n },\n addChat(message) {\n if (state.chat.some((existing) => existing.id === message.id)) return;\n const chat = [...state.chat, message];\n // A chat message carries its sender's name — another source, same book.\n const names = learnName(state.names, message.identity, message.displayName);\n commit({ ...state, chat: chat.slice(-CHAT_LIMIT), names });\n },\n loadChat(messages) {\n const known = new Set(state.chat.map((message) => message.id));\n const merged = [...messages.filter((message) => !known.has(message.id)), ...state.chat].sort(\n (a, b) => (a.at < b.at ? -1 : a.at > b.at ? 1 : 0),\n );\n const names = learnNames(\n state.names,\n messages.map((message) => ({ identity: message.identity, displayName: message.displayName })),\n );\n commit({ ...state, chat: merged.slice(-CHAT_LIMIT), chatLoaded: true, chatHistoryError: null, names });\n },\n settleChat(localId, next) {\n const index = state.chat.findIndex((message) => message.id === localId);\n if (index === -1) return;\n const current = state.chat[index] as RoomChatMessage;\n let replacement: RoomChatMessage;\n if (\"failed\" in next && typeof next.failed === \"string\" && !(\"id\" in next)) {\n replacement = { ...current, failed: next.failed };\n } else {\n replacement = next as RoomChatMessage;\n }\n // The saved copy may ALREADY be here (the room packet beat the response):\n // then the pending one simply goes.\n const duplicate =\n replacement.id !== localId && state.chat.some((message) => message.id === replacement.id);\n const chat = duplicate\n ? state.chat.filter((message) => message.id !== localId)\n : state.chat.map((message, position) => (position === index ? replacement : message));\n commit({ ...state, chat });\n },\n addReaction(reaction) {\n commit({ ...state, reactions: [...state.reactions, reaction] });\n },\n expireReactions(now) {\n const live = state.reactions.filter((reaction) => now - reaction.at < REACTION_TTL_MS);\n if (live.length === state.reactions.length) return;\n commit({ ...state, reactions: live });\n },\n setRecording(next, by, source, recordingId = null) {\n // 🚨 THE DATABASE WINS (D16). A member receives every transition TWICE —\n // the `meet_recordings` row over Postgres Changes and a\n // `matrx.meet.recording` packet in the room — and whichever is slower\n // must not be able to drag the indicator backwards.\n //\n // The rule is about ONE recording, not about the meeting: a meeting can\n // be recorded again, and the second recording's first word is not a\n // contradiction of the first one's ending. So the durable state stands\n // against anything that is about the SAME recording, and against a\n // sourceless update while a recording is still in flight.\n // `record` always wins. The other two are refused when they would\n // contradict the durable word rather than continue past it:\n //\n // * `local` is this browser acting NOW — a host pressing Start again on a\n // meeting whose last recording is over. It is refused only while a\n // recording is genuinely in flight, where a stale optimistic patch\n // could drag a live indicator backwards.\n // * `room` carries the recording's id, so a LATE packet about the\n // recording that just finished is told apart from the FIRST packet of\n // the next one. Same recording: refused. Different recording: refused\n // only while the durable one is still in flight.\n if (state.recordingSource === \"record\" && source !== \"record\") {\n const aboutTheSameRecording =\n source === \"room\" &&\n (recordingId === null ||\n state.recordingId === null ||\n recordingId === state.recordingId);\n if (aboutTheSameRecording || isRecordingInFlight(state.recording)) return;\n }\n if (\n state.recording === next &&\n state.recordingStartedBy === by &&\n state.recordingSource === source &&\n state.recordingId === (recordingId ?? state.recordingId)\n ) {\n // Identity-stable: an unchanged state must not wake every subscriber.\n return;\n }\n commit({\n ...state,\n recording: next,\n recordingStartedBy: by,\n recordingSource: source,\n recordingId: recordingId ?? state.recordingId,\n });\n },\n upsertLobby(entry) {\n const index = state.lobby.findIndex((existing) => existing.identity === entry.identity);\n const lobby =\n index === -1\n ? [...state.lobby, entry]\n : state.lobby.map((existing, position) => (position === index ? entry : existing));\n commit({ ...state, lobby });\n },\n setAdmission(identity, admissionState, by) {\n commit({\n ...state,\n lobby: state.lobby.map((entry) =>\n entry.identity === identity\n ? {\n ...entry,\n state: admissionState,\n decidedAt: new Date().toISOString(),\n decidedBy: by,\n }\n : entry,\n ),\n });\n },\n learn(entries) {\n const names = learnNames(state.names, entries);\n // Identity-stable: learning nothing must not wake every subscriber, and\n // this is called on every roster event and every durable row.\n if (names === state.names) return;\n commit({ ...state, names });\n },\n ingestCaption(segment) {\n // A caption's roster lookup is a source of names like any other.\n const names = learnName(state.names, segment.identity, segment.speaker);\n const transcript = mergeCaption(state.transcript, segment);\n if (transcript === state.transcript && names === state.names) return;\n commit({ ...state, transcript, names });\n },\n ingestRecord(segment) {\n // 🚨 THE DURABLE ROW'S `speaker` IS THE BEST NAME THERE IS: the note-taker\n // wrote it from `meet_participants`, which is where \"Ada Lovelace\" lived\n // while the guest's screen was printing `guest:c8-spk-1`.\n const names = learnName(state.names, segment.identity, segment.speaker);\n const transcript = mergeRecord(state.transcript, segment);\n if (transcript === state.transcript && names === state.names) return;\n commit({ ...state, transcript, names });\n },\n upsertNote(note) {\n const index = state.notes.findIndex((existing) => existing.id === note.id);\n if (index === -1) {\n commit({ ...state, notes: [...state.notes, note] });\n return;\n }\n const existing = state.notes[index];\n // Identity-stable: an unchanged note must not wake `useSyncExternalStore`.\n // 🚨 `source` is part of \"unchanged\" and that is load-bearing, not\n // cosmetic: when the room copy and the database copy carry the same words,\n // dropping the second arrival would leave the note marked `\"room\"` forever\n // — and the precedence rule below would then let a LATER stale packet\n // overwrite a row the database had already confirmed.\n if (\n existing !== undefined &&\n existing.text === note.text &&\n existing.kind === note.kind &&\n existing.supersededBy === note.supersededBy &&\n existing.source === note.source\n ) {\n return;\n }\n // 🚨 THE DATABASE WINS (D16, MRI-A12). The identical row arrives on two\n // transports — a `meet_notes` row over Postgres Changes and a\n // `matrx.meet.note` packet on the media plane — and whichever is slower\n // must not be able to undo the other. A `\"room\"` copy never overwrites a\n // `\"record\"` one; a `\"record\"` copy always overwrites a `\"room\"` one.\n // Without this, a re-run that rewrote a note could flip a member's screen\n // back to the superseded wording purely on arrival order.\n if (existing !== undefined && existing.source === \"record\" && note.source === \"room\") {\n return;\n }\n commit({\n ...state,\n notes: state.notes.map((entry, position) => (position === index ? note : entry)),\n });\n },\n announceWrapUp(announcement) {\n const current = state.wrapUp;\n if (current !== null && current.at === announcement.at) return;\n commit({ ...state, wrapUp: announcement });\n },\n setLocalTrack(kind, next) {\n const current = state.media[kind];\n // Identity-stable: an unchanged track must not wake `useSyncExternalStore`.\n if (\n current.enabled === next.enabled &&\n current.unavailable?.code === next.unavailable?.code &&\n current.unavailable?.message === next.unavailable?.message\n ) {\n return;\n }\n commit({ ...state, media: { ...state.media, [kind]: next } });\n },\n reset() {\n // A person's own media choices outlive a room: they are theirs, per browser.\n commit({ ...EMPTY, effects: state.effects });\n },\n };\n}\n","/**\n * MEETINGS — the lobby, the host powers, and the durable link.\n *\n * A meeting is a room plus scheduling, lobby and host metadata (D3). Everything\n * here is about the moments OUTSIDE the media session, which is exactly why it\n * cannot ride LiveKit's data plane: a guest waiting in the lobby is not in the\n * LiveKit room yet, by construction. The lobby therefore lives on the meet-room\n * realtime channel.\n *\n * 🚨 THE THREE THINGS THAT MAKE GUEST JOIN SAFE (D6)\n *\n * 1. **The link is an identity, not a session.** A durable slug resolves before,\n * during, and after the scheduled time, and a recurring meeting keeps ONE\n * link. Nothing here mints a per-occurrence URL.\n * 2. **A guest's capability is the TOKEN, and nothing else.** They are scoped to\n * exactly one room. There is no guest row this client writes that could grant\n * anything, and no client-side \"is this person allowed\" branch.\n * 3. **Admission is a SERVER decision, recorded.** `admit` is an RPC; the\n * broadcast that tells the knocker is a NOTIFICATION of that decision, never\n * the decision itself. Two hosts clicking admit is the ordinary case, and the\n * RPC is what makes it idempotent.\n *\n * Host powers are checked against the role the SERVER minted into the token\n * (see `room.ts`), and the UI hides what an actor cannot do rather than\n * rendering a dead button (no dead ends).\n */\n\nimport type { ChannelHandle, RealtimeManager } from \"@ai-matrx/realtime\";\nimport { MEET_EVENTS, meetingTopic, roomTopic } from \"./channels\";\nimport type { MeetApi } from \"./api\";\nimport { MeetError } from \"./errors\";\nimport { readServerRefusal } from \"./ai\";\nimport type { MeetRepository } from \"./repository\";\nimport { effectiveRole, type MeetStore } from \"./store\";\nimport { MEET_ROUTES } from \"./tokens\";\nimport {\n asParticipantIdentity,\n isHostRole,\n isGuest,\n ROLE_RANK,\n type LobbyEntry,\n type MeetIdentity,\n type MeetParticipant,\n type MeetingAttendee,\n type MeetingId,\n type MeetingRecord,\n type ParticipantIdentity,\n type ParticipantRole,\n type RecordingState,\n type RoomName,\n type UserId,\n} from \"./types\";\n\nexport interface MeetingSessionOptions {\n manager: RealtimeManager;\n repository: MeetRepository;\n store: MeetStore;\n identity: MeetIdentity;\n /**\n * The ONE org-aware aidream client (MRI-A16) — `endForEveryone` is a SERVER\n * decision (MRI-A6), and every request it makes carries the organization.\n */\n api: MeetApi;\n onDiagnostic?: ((event: { level: \"info\" | \"warn\" | \"error\"; message: string; remedy?: string }) => void) | undefined;\n /**\n * 🚨 THE HOST ADMITTED *US*. Called exactly once per admission verdict that\n * names this participant, and only for `admitted`.\n *\n * Admission is not a UI state change: a lobby token is minted with\n * `canPublish: false` and `canSubscribe: false`, so the waiting room can only\n * become a room by minting a NEW token. Before this existed the waiting room\n * said \"you will join automatically once you are admitted\" and then waited\n * forever — a sentence on screen that was not true. The provider wires this\n * to `engine.rejoin()`.\n */\n onAdmitted?: (() => void) | undefined;\n /**\n * 🚨 THE HOST DENIED *US*. Called once per denial verdict that names this\n * knocker. Without it the waiting room kept promising \"you will join\n * automatically\" to a person the host had already turned away (production\n * 2026-09-27). The provider wires it to `engine.rejoin()`: the server then\n * refuses the mint with its own sentence (\"The host did not admit you…\"),\n * so the words on screen are the server's decision, never the client's guess.\n */\n onDenied?: (() => void) | undefined;\n}\n\nexport interface MeetingSession {\n /** Subscribe to the room's out-of-band plane. Hosts see knocks; guests see verdicts. */\n watch(roomName: RoomName): void;\n /**\n * Subscribe to the MEETING RECORD's durable feed — transcript segments, notes,\n * and the meeting row itself (which is where the note-taker's state lives).\n * Reconnecting IS re-reading: the backfill door re-reads all three, because\n * realtime has no replay and a socket blip would otherwise leave a transcript\n * permanently missing the minute nobody noticed.\n */\n watchMeeting(meetingId: MeetingId): void;\n /** A guest (or a late arrival at a locked room) announces themselves. */\n knock(roomName: RoomName): void;\n admit(entry: LobbyEntry, admitted: boolean): Promise<void>;\n admitAll(): Promise<void>;\n setLock(locked: boolean): Promise<MeetingRecord>;\n /** End it for everyone, through the server (MRI-A6). */\n endForEveryone(): Promise<EndMeetingResult>;\n dispose(): void;\n}\n\n/** Can `actor` moderate `target`? A host outranks a co-host outranks everyone. */\nexport function canModerateParticipant(\n actor: MeetParticipant | undefined,\n target: MeetParticipant | undefined,\n): boolean {\n if (actor === undefined || target === undefined) return false;\n if (actor.role === \"participant\") return false;\n if (actor.identity === target.identity) return false;\n // A co-host cannot remove the host. Without this rank check, \"host controls\"\n // is a mutual-eviction button.\n return ROLE_RANK[actor.role] > ROLE_RANK[target.role];\n}\n\nexport function roleOf(\n participants: readonly MeetParticipant[],\n identity: ParticipantIdentity | null,\n): ParticipantRole {\n if (identity === null) return \"participant\";\n return participants.find((p) => p.identity === identity)?.role ?? \"participant\";\n}\n\n/**\n * What ending a meeting produced. `served: false` is the honest answer from a\n * server that has not landed `POST /v1/meet/end` yet (MRI-A6) — the control is\n * real, the refusal is a sentence, and nothing pretends the meeting ended.\n */\nexport interface EndMeetingResult {\n readonly endedAt: string | null;\n readonly served: boolean;\n}\n\n/** The sentence a server without MRI-A6 earns. Pinned so every surface says it. */\nexport const END_MEETING_NOT_SERVED =\n \"Ending a meeting is not available on this server yet\";\n\n/**\n * One durable `meet_participants` row as a lobby entry, or `null` when it is\n * not one. A row that has been decided is not a knocker; the panel shows people\n * who are WAITING, and `store.upsertLobby` keyed by identity is what lets the\n * table and the broadcast be two copies of one person rather than two rows.\n */\nfunction lobbyEntryFrom(attendee: MeetingAttendee): LobbyEntry | null {\n if (attendee.admissionState !== \"knocking\") return null;\n return {\n identity: attendee.identity,\n displayName: attendee.displayName,\n avatarUrl: attendee.avatarUrl,\n userId: attendee.userId,\n state: \"knocking\",\n knockedAt: attendee.joinedAt ?? new Date().toISOString(),\n decidedAt: null,\n decidedBy: null,\n };\n}\n\nexport function createMeetingSession(options: MeetingSessionOptions): MeetingSession {\n const { manager, repository, store, identity } = options;\n let channel: ChannelHandle | null = null;\n let meetingChannel: ChannelHandle | null = null;\n\n /**\n * The meeting row, for anyone who may be in it. A member or a person the\n * meeting was shared with reads it under RLS; a signed-in person from ANOTHER\n * organization who followed the link cannot, and gets the same row through\n * the link door (`meet_meeting_by_slug`) a guest uses — the server lets them\n * in by the link, so the screen must not fail them for holding it.\n */\n async function readMeeting(meetingId: MeetingId): Promise<MeetingRecord> {\n try {\n return await repository.meeting(meetingId);\n } catch (error) {\n const slug = store.snapshot().meeting?.slug;\n if (slug === undefined) throw error;\n return repository.meetingBySlug(slug);\n }\n }\n\n function requireHostUser(operation: string): UserId {\n // THE SAME PREDICATE THE UI RENDERS FROM (MRI-A11). Reading only the roster\n // here — while the control renders from the token grant — is how a host\n // control becomes a button that throws the moment it is used.\n if (identity.userId === null || !isHostRole(effectiveRole(store.snapshot()))) {\n throw new MeetError(\n \"forbidden\",\n `${operation}: this participant is not a host`,\n \"Host powers come from the server-minted token metadata and are enforced by the RPC. \" +\n \"Hide the control rather than rendering a button that will be refused.\",\n );\n }\n return identity.userId;\n }\n\n /**\n * ONE definition of \"who am I in the lobby\", used to knock AND to hear back.\n * It MUST equal the identity the token route writes on the lobby row\n * (aidream `participant_identity`: `user:<uuid>` or `guest:<device>`). A bare\n * uuid here gave a signed-in outsider two lobby entries on the host's panel;\n * admitting the bare one decided a row nobody held and they waited forever.\n */\n function knockIdentity(): ParticipantIdentity {\n return asParticipantIdentity(\n identity.userId !== null ? `user:${identity.userId}` : `guest:${identity.deviceId}`,\n );\n }\n\n function requireMeeting(operation: string): MeetingRecord {\n const meeting = store.snapshot().meeting;\n if (meeting === null) {\n throw new MeetError(\n \"misconfigured\",\n `${operation}: no meeting is loaded`,\n \"Ad-hoc call rooms have no meeting record and therefore no lobby or lock. Use \" +\n \"joinMeeting()/scheduleMeeting() when you need those powers.\",\n );\n }\n return meeting;\n }\n\n return {\n watch(roomName) {\n channel?.close();\n channel = manager.open({\n topic: roomTopic(roomName),\n broadcast: [\n {\n event: MEET_EVENTS.knock,\n onMessage: (message) => {\n store.upsertLobby(message.data as LobbyEntry);\n },\n },\n {\n event: MEET_EVENTS.admission,\n onMessage: (message) => {\n const verdict = message.data as {\n identity: string;\n admitted: boolean;\n by: string | null;\n };\n const decided = asParticipantIdentity(verdict.identity);\n store.setAdmission(\n decided,\n verdict.admitted ? \"admitted\" : \"denied\",\n verdict.by === null ? null : (verdict.by as UserId),\n );\n // THE VERDICT IS ABOUT US, AND IT IS YES. The identity compared\n // here is the KNOCK identity (see `knock()` below), which is what\n // the host's admit RPC and this broadcast both carry — not the\n // LiveKit participant identity, which a lobby joiner does not\n // have yet because they are not in the room.\n if (decided === knockIdentity()) {\n if (verdict.admitted) options.onAdmitted?.();\n else options.onDenied?.();\n }\n },\n },\n {\n event: MEET_EVENTS.lock,\n onMessage: (message) => {\n const { locked } = message.data as { locked: boolean };\n const meeting = store.snapshot().meeting;\n store.patch({\n locked,\n ...(meeting !== null ? { meeting: { ...meeting, locked } } : {}),\n });\n },\n },\n {\n event: MEET_EVENTS.recording,\n onMessage: (message) => {\n const payload = message.data as { state: string; by: string | null };\n // EVERY participant renders the indicator, guests included (R5).\n // This is why recording state is broadcast rather than derived\n // from a host-only read. It is `\"room\"`, so the durable row\n // outranks it (D16) — see `store.setRecording`.\n store.setRecording(\n payload.state as RecordingState,\n payload.by === null ? null : (payload.by as UserId),\n \"room\",\n );\n },\n },\n ],\n // THE BACKFILL DOOR. A host whose socket blipped must not miss a knock:\n // re-reading the meeting restores lock/recording truth, and knockers\n // re-announce on their own timer.\n onBackfill: async () => {\n const meeting = store.snapshot().meeting;\n if (meeting === null) return;\n const fresh = isGuest(identity)\n ? await repository.meetingBySlug(meeting.slug)\n : await readMeeting(meeting.id);\n store.patch({ meeting: fresh, locked: fresh.locked });\n },\n });\n },\n\n watchMeeting(meetingId) {\n meetingChannel?.close();\n meetingChannel = null;\n if (isGuest(identity)) {\n options.onDiagnostic?.({\n level: \"info\",\n message: \"Guest notes and captions arrive through the live meeting room; saved history is not available without a session.\",\n remedy: \"Sign in with access to this meeting to reload saved notes and transcript history.\",\n });\n return;\n }\n meetingChannel = manager.open({\n topic: meetingTopic(meetingId),\n postgresChanges: [\n {\n event: \"*\",\n schema: repository.schema,\n table: repository.tables.transcripts,\n filter: `meeting_id=eq.${meetingId}`,\n rowId: (row) => (typeof row[\"id\"] === \"string\" ? row[\"id\"] : undefined),\n onChange: ({ row }) => {\n // D16: THE ROW IS THE TRANSCRIPT. It replaces the caption that\n // showed the same words a moment earlier.\n if (row !== null) store.ingestRecord(repository.projectSegment(row));\n },\n },\n {\n event: \"*\",\n schema: repository.schema,\n table: repository.tables.notes,\n filter: `meeting_id=eq.${meetingId}`,\n rowId: (row) => (typeof row[\"id\"] === \"string\" ? row[\"id\"] : undefined),\n onChange: ({ row }) => {\n // Upsert, not append: a re-run of the wrap-up rewrites the SAME\n // row ids by design, and appending would show every note twice.\n if (row !== null) store.upsertNote(repository.projectNote(row));\n },\n },\n {\n // 🚨 THE LOBBY IS A TABLE, NOT ONLY A CHANNEL (MRI-A16). A guest\n // knocks by writing `admission_state='knocking'` AND broadcasting;\n // through 0.4.7 the host's People panel rendered only the broadcast,\n // so a knocker whose packet landed before this browser opened the\n // channel — a host who joined second, reloaded, or slept a laptop —\n // was INVISIBLE while the guest sat in the waiting room forever. A\n // host can read this table; a guest cannot, and gets no lobby list\n // at all, which is correct.\n event: \"*\",\n schema: repository.schema,\n table: repository.tables.participants,\n filter: `meeting_id=eq.${meetingId}`,\n rowId: (row) => (typeof row[\"id\"] === \"string\" ? row[\"id\"] : undefined),\n onChange: ({ row }) => {\n if (row === null) return;\n const attendee = repository.projectAttendee(row);\n store.learn([attendee]);\n const entry = lobbyEntryFrom(attendee);\n if (entry !== null) {\n store.upsertLobby(entry);\n return;\n }\n // 🚨 A DECIDED ROW MUST CLEAR THE DOOR. Admitting a guest from\n // another tab writes `admitted` here, and simply ignoring the row\n // would leave this host's panel offering to admit somebody who is\n // already in the meeting — a ghost knocker who can never be\n // dismissed. The durable row is the verdict, wherever it was made.\n store.setAdmission(attendee.identity, attendee.admissionState, null);\n },\n },\n {\n event: \"*\",\n schema: repository.schema,\n table: repository.tables.recordings,\n filter: `meeting_id=eq.${meetingId}`,\n rowId: (row) => (typeof row[\"id\"] === \"string\" ? row[\"id\"] : undefined),\n onChange: ({ row }) => {\n // 🚨 THE INDICATOR RENDERS THE DURABLE STATE, not this browser's\n // hope. Through 0.4.7 nothing subscribed here, so the only\n // transitions the store ever saw were the optimistic `starting`\n // and `stopping` THIS client patched — and the indicator sat on\n // \"Starting recording…\" for a whole meeting while a healthy\n // egress ran, then \"Stopping recording…\" forever (MRI-C8).\n if (row === null) return;\n const recording = repository.projectRecording(row);\n store.setRecording(recording.state, recording.startedBy, \"record\", recording.id);\n },\n },\n {\n event: \"*\",\n schema: repository.schema,\n table: repository.tables.meetings,\n filter: `id=eq.${meetingId}`,\n rowId: (row) => (typeof row[\"id\"] === \"string\" ? row[\"id\"] : undefined),\n onChange: ({ row }) => {\n // The note-taker's state lives on this row's metadata (D9/MRI-A2),\n // so this subscription is what keeps each server-recorded state\n // current on screen without a reload.\n if (row === null) return;\n const meeting = repository.projectMeeting(row);\n store.patch({ meeting, locked: meeting.locked });\n },\n },\n ],\n // THE BACKFILL DOOR. Realtime has no replay: everything that happened\n // while the socket was down is gone. Re-reading all three is what keeps\n // a recovered surface from looking healthy and being wrong.\n onBackfill: async () => {\n const [meeting, transcript, notes, recordings, attendees] = await Promise.all([\n readMeeting(meetingId),\n repository.transcript(meetingId),\n repository.notes(meetingId),\n repository.recordings(meetingId),\n repository.attendees(meetingId),\n ]);\n store.patch({ meeting, locked: meeting.locked });\n for (const segment of transcript) store.ingestRecord(segment);\n for (const note of notes) store.upsertNote(note);\n // A socket blip must not leave the indicator saying something the\n // database stopped agreeing with ten minutes ago. `recordings` is\n // newest first.\n const latest = recordings[0];\n if (latest !== undefined) {\n store.setRecording(latest.state, latest.startedBy, \"record\", latest.id);\n }\n // Everyone the durable rows know a name for, and every knocker still\n // waiting. A host who reloads must not lose a person at the door.\n store.learn(attendees);\n for (const attendee of attendees) {\n const entry = lobbyEntryFrom(attendee);\n if (entry !== null) {\n store.upsertLobby(entry);\n } else {\n // The same rule on the backfill door: a host who reloads must not\n // find people at the door who were admitted while they were gone.\n store.setAdmission(attendee.identity, attendee.admissionState, null);\n }\n }\n },\n });\n // The FIRST read is the same read: a surface that joins a meeting already\n // in progress must see what was already said.\n meetingChannel.requestBackfill(\"manual\");\n },\n\n knock(roomName) {\n const handle = channel ?? manager.open({ topic: roomTopic(roomName) });\n channel = handle;\n const entry: LobbyEntry = {\n identity: knockIdentity(),\n displayName: identity.displayName,\n avatarUrl: identity.avatarUrl,\n userId: identity.userId,\n state: \"knocking\",\n knockedAt: new Date().toISOString(),\n decidedAt: null,\n decidedBy: null,\n };\n store.upsertLobby(entry);\n handle.send(MEET_EVENTS.knock, entry);\n },\n\n async admit(entry, admitted) {\n const by = requireHostUser(\"meet.admit\");\n const meeting = requireMeeting(\"meet.admit\");\n // The RPC IS the decision. The broadcast below only tells the knocker,\n // who has no database read of their own — they are a guest.\n await repository.admit({\n meetingId: meeting.id,\n identity: entry.identity,\n admitted,\n byUserId: by,\n });\n // UPSERT, not patch-if-present. A host can decide on a knock this store\n // never saw (the knock arrived before this tab subscribed, or a second\n // host is deciding), and `setAdmission` on an unknown identity would do\n // nothing at all — a silent no-op behind a button that looked like it\n // worked.\n store.upsertLobby({\n ...entry,\n state: admitted ? \"admitted\" : \"denied\",\n decidedAt: new Date().toISOString(),\n decidedBy: by,\n });\n channel?.send(MEET_EVENTS.admission, {\n identity: entry.identity,\n admitted,\n by,\n });\n },\n\n async admitAll() {\n const knocking = store.snapshot().lobby.filter((entry) => entry.state === \"knocking\");\n for (const entry of knocking) {\n await this.admit(entry, true);\n }\n },\n\n async setLock(locked) {\n const by = requireHostUser(\"meet.setLock\");\n const meeting = requireMeeting(\"meet.setLock\");\n const updated = await repository.setLock(meeting.id, locked, by);\n store.patch({ meeting: updated, locked: updated.locked });\n channel?.send(MEET_EVENTS.lock, { locked: updated.locked });\n return updated;\n },\n\n /**\n * END IT FOR EVERYONE — a SERVER decision, not a row this client updates.\n *\n * 0.2.1 called the `meet_end_meeting` RPC directly, which ended the meeting\n * in the database while LiveKit kept the room open and the note-taker kept\n * writing into an ended meeting. `POST /v1/meet/end` re-checks the host,\n * closes the room, and triggers the wrap-up — one decision, one place\n * (MRI-A6).\n *\n * 🚨 A SERVER THAT HAS NOT LANDED THAT ROUTE ANSWERS 404, and that is\n * reported as a sentence, never as a dead control and never as a success.\n */\n async endForEveryone() {\n requireHostUser(\"meet.endForEveryone\");\n const meeting = requireMeeting(\"meet.endForEveryone\");\n const response = await options.api.request({\n path: MEET_ROUTES.meetingEnd,\n method: \"POST\",\n requireAuth: true,\n operation: \"meet.endForEveryone\",\n body: {\n meeting_id: meeting.id,\n organization_id: identity.organizationId,\n },\n });\n if (response.status === 404) {\n return { endedAt: null, served: false };\n }\n if (!response.ok) {\n let body: unknown = null;\n try {\n body = await response.json();\n } catch {\n body = null;\n }\n const refusal = readServerRefusal(body);\n throw new MeetError(\n response.status === 403 ? \"forbidden\" : \"transport\",\n refusal?.reason ?? `meet.endForEveryone: the server answered ${response.status}`,\n refusal?.remedy !== undefined && refusal.remedy.length > 0\n ? refusal.remedy\n : \"The meeting is still running. Only a host may end it, and the server \" +\n \"re-checks that — being a host on this screen is not the decision.\",\n );\n }\n let payload: unknown = null;\n try {\n payload = await response.json();\n } catch {\n payload = null;\n }\n const row =\n typeof payload === \"object\" && payload !== null\n ? (payload as Record<string, unknown>)\n : {};\n const endedAt =\n typeof row[\"ended_at\"] === \"string\" ? row[\"ended_at\"] : new Date().toISOString();\n const current = store.snapshot().meeting;\n if (current !== null) store.patch({ meeting: { ...current, endedAt } });\n return { endedAt, served: true };\n },\n\n dispose() {\n channel?.close();\n channel = null;\n meetingChannel?.close();\n meetingChannel = null;\n },\n };\n}\n\n/**\n * A durable public slug. Lowercase, hyphenated, and deliberately readable —\n * people read these aloud on phone calls. The alphabet excludes the four\n * characters that get misheard (0/O, 1/l).\n */\nconst SLUG_ALPHABET = \"abcdefghijkmnpqrstuvwxyz23456789\";\n\nexport function meetingSlug(random: () => number = Math.random): string {\n const group = (length: number): string =>\n Array.from({ length }, () => {\n const index = Math.floor(random() * SLUG_ALPHABET.length);\n return SLUG_ALPHABET[index] ?? \"a\";\n }).join(\"\");\n return `${group(3)}-${group(4)}-${group(3)}`;\n}\n\n/** The link a host copies. ONE shape, so every surface produces the same URL. */\nexport function meetingLink(baseUrl: string, slug: string): string {\n return `${baseUrl.replace(/\\/+$/, \"\")}/meet/${slug}`;\n}\n","/**\n * THE DATA CONTRACT — the ONE place a meet table or RPC name exists.\n *\n * 🚨 **STATE OF THE SCHEMA (read this before believing a green test).** The\n * `communication.meet_*` tables below are the canonical schema DESIGNED by this\n * package per R8; they are **not deployed to Matrx Main yet**. They were placed\n * by inspecting the live database on 2026-08-31: `communication` is the schema\n * that already holds `dm_*` (messaging) and `sms_*` (telephony), so meet takes\n * the `meet_*` prefix in the same schema rather than inventing a new one. Until\n * the migration lands, every read here fails LOUDLY with `not-found` and a\n * remedy naming this file — never silently, and never with a fabricated row.\n * The migration and the aidream server half are one deliverable; see FEATURE.md\n * § Deliberately NOT in this package.\n *\n * Four rules hold this file together — the same four that hold messaging's:\n *\n * 1. **Org is explicit on every write (R5).** Not defaulted by a trigger we\n * hope fires — passed, and refused in-package when absent.\n * 2. **Authorization is the database's job.** There is no permission branch in\n * this file. An RPC that says no is a `forbidden` MeetError, never a\n * client-side re-decision. Guest capability is scoped by the room TOKEN, not\n * by a row this client could write.\n * 3. **Writes go through SECURITY DEFINER RPCs; reads are RLS-backed table\n * reads** (C17's hybrid ruling). Every write here is an RPC, which is also\n * what keeps admission and settle-a-call ATOMIC — two hosts clicking \"admit\"\n * and a callee accepting on two devices are the ordinary case, not the edge.\n * 4. **Pagination is keyset, terminated by a unique column.** `(created_at,\n * id)` — never a timestamp alone, which duplicates or skips rows whenever\n * two share a millisecond.\n *\n * The Supabase client is accepted STRUCTURALLY, through the shape\n * `@ai-matrx/messaging` already owns. One definition of \"a Supabase client\" for\n * the whole communications family; this package adds no second copy.\n *\n * 🚨 AND THE PUBLIC BOUNDARY IS THE SHALLOW ONE (0.2.1). `RepositoryOptions`\n * and `<MeetProvider client>` take `MessagingSupabaseClient` — method names and\n * arity, results as `unknown` — never the rich `SupabaseLike`. Checking a\n * host's real `SupabaseClient<Database>` (built from generated types) against\n * the rich shape makes tsc chase PostgREST's schema machinery until it bails\n * with `TS2589: Type instantiation is excessively deep and possibly infinite`,\n * so the only way to pass the client a host ALREADY HAS was a cast — which is\n * what the first real consumer had to write (register MRI-D1). Messaging 0.9.0\n * learned this and wrote it down; this package did not apply the lesson until\n * now. The rich shape stays the INTERNAL contract, and we narrow to it ONCE,\n * here, in-package.\n */\n\nimport type { MessagingSupabaseClient, SupabaseLike } from \"@ai-matrx/messaging\";\nimport { invalidResponse, MeetError, normalizeMeetError } from \"./errors\";\nimport {\n asCallId,\n asMeetingId,\n asOrganizationId,\n asParticipantIdentity,\n asRoomName,\n asUserId,\n type CallId,\n type CallInvite,\n type CallMode,\n type CallState,\n type JsonObject,\n type MeetingId,\n type MeetingKind,\n type MeetingAttendee,\n type MeetingNote,\n type MeetingRecord,\n type ParticipantRole,\n type AdmissionState,\n type OrganizationId,\n type RecordingPolicy,\n type RecordingRecord,\n type RecordingRetention,\n type RecordingState,\n type RoomName,\n type TranscriptSegment,\n type UserId,\n type InviteeInput,\n type InviteeRole,\n type MeetingChanges,\n type MeetingInvitee,\n type MeetingOccurrence,\n type MeetingSettings,\n type OccurrenceOverride,\n type OccurrenceState,\n type RsvpAnswer,\n type RsvpInvitation,\n type RsvpState,\n type UpcomingOccurrence,\n} from \"./types\";\n\n/** The schema. Meet is never in `public`. */\nexport const MEET_SCHEMA = \"communication\";\n\nexport const TABLES = {\n meetings: \"meet_meetings\",\n participants: \"meet_participants\",\n invites: \"meet_call_invites\",\n recordings: \"meet_recordings\",\n transcripts: \"meet_transcript_segments\",\n notes: \"meet_notes\",\n /** Wave 1 (0.8): who a meeting was sent to, and what they answered. */\n invitees: \"meet_invitees\",\n /** Wave 1 (0.8): one occurrence of a series cancelled or moved. */\n occurrenceOverrides: \"meet_occurrence_overrides\",\n} as const;\n\nexport const RPCS = {\n /** Atomic: create the invite row and stamp its expiry in one statement. */\n createCallInvite: \"meet_create_call_invite\",\n /** Atomic settle. Refuses a transition out of a terminal state. */\n settleCallInvite: \"meet_settle_call_invite\",\n /** Every invite still ringing this user — the reconnect backfill door. */\n pendingCallInvites: \"meet_pending_call_invites\",\n /** Instant meeting, or the durable one behind a recurring link. */\n getOrCreateMeeting: \"meet_get_or_create_meeting\",\n /** Resolve a durable public link, before/during/after its scheduled time. */\n meetingBySlug: \"meet_meeting_by_slug\",\n admit: \"meet_admit_participant\",\n setLock: \"meet_set_lock\",\n endMeeting: \"meet_end_meeting\",\n recordConsent: \"meet_record_consent\",\n /*\n * ── MEET WAVE 1 — management (0.8). Every write is a SECURITY DEFINER door\n * authorized by the meeting's host or a real iam grant (editor to change,\n * admin = co-host to archive or name a co-host) — never an organization\n * match. After any of these writes, call `announceMeeting` so the server\n * sends invitations / updates / cancellations and re-queues reminders.\n */\n /** Schedule with every setting at create; unset settings come from the knobs. */\n scheduleMeeting: \"meet_schedule_meeting\",\n /** Edit / reschedule — a JSON patch with a version compare-and-swap. */\n updateMeeting: \"meet_update_meeting\",\n /** Cancel is a state (`cancelled_at`); the link keeps resolving. */\n cancelMeeting: \"meet_cancel_meeting\",\n /** Archive (soft delete) — the invitations and exceptions cascade. */\n archiveMeeting: \"meet_archive_meeting\",\n restoreMeeting: \"meet_restore_meeting\",\n /** Cancel, move or restore ONE occurrence of a series by its original start. */\n setOccurrence: \"meet_set_occurrence\",\n addInvitees: \"meet_add_invitees\",\n setInviteeRole: \"meet_set_invitee_role\",\n removeInvitee: \"meet_remove_invitee\",\n /** A signed-in invitee answers for themselves. */\n respond: \"meet_respond\",\n /** The emailed RSVP link (no account): read and answer. */\n invitationByToken: \"meet_invitation_by_token\",\n respondByToken: \"meet_respond_by_token\",\n /** One meeting's occurrences between two instants (INVOKER — the reader's RLS). */\n meetingOccurrences: \"meet_meeting_occurrences\",\n /** Every occurrence the reader can see between two instants — the Upcoming list. */\n occurrencesBetween: \"meet_occurrences_between\",\n /*\n * ── MEET WAVE 3 — after the meeting. Both INVOKER (the reader's RLS) and both\n * scoped to the reader's OWN meetings (host, invitee, attended) — RLS is the\n * ceiling, never the view.\n */\n /** The recordings library. */\n myRecordings: \"meet_my_recordings\",\n /** Titles, agendas, current notes and final transcript lines; snippets mark hits with ⟦ ⟧. */\n search: \"meet_search\",\n} as const;\n\n/**\n * THE RPCs THAT RETURN NOTHING, verified against the live database\n * (`pg_get_function_result`, 2026-09-08). They go through `guardVoid`; every\n * other RPC returns a row and goes through `guard`. Wiring a void RPC to\n * `guard` makes a SUCCESSFUL write look like a failure — see `guardVoid`.\n */\nexport const VOID_RPCS: readonly string[] = [RPCS.admit, RPCS.recordConsent];\n\nconst MEETING_COLUMNS =\n \"id,organization_id,room_name,slug,title,kind,host_user_id,scheduled_for,\" +\n \"scheduled_duration_minutes,started_at,ended_at,locked,lobby_enabled,\" +\n \"recording_policy,ai_enabled,metadata,\" +\n // Wave 1 (0.8).\n \"time_zone,agenda,recurrence_rule,join_before_host,cancelled_at,cancellation_reason,\" +\n \"deleted_at,calendar_sequence,version\";\n\nconst INVITEE_COLUMNS =\n \"id,meeting_id,invitee_user_id,email,display_name,role,rsvp_state,responded_at,\" +\n \"rsvp_note,last_sent_sequence,last_sent_at\";\n\n/**\n * The invite row's columns. Not used by a `select` today — every invite read\n * and write goes through an RPC (C17's hybrid: writes are SECURITY DEFINER,\n * and a settle must be atomic) — but it is part of the contract S2's migration\n * has to satisfy, and it is what `projectInvite` reads out of an RPC's return\n * row. Keep it in step with that function.\n */\nconst INVITE_COLUMNS =\n \"id,organization_id,room_name,mode,caller_user_id,caller_name,caller_avatar_url,\" +\n \"callee_ids,conversation_id,created_at,expires_at,state,decline_message\";\n\nconst RECORDING_COLUMNS =\n \"id,meeting_id,state,started_at,ended_at,started_by,file_id,failure_reason\";\n\n/**\n * THE TRANSCRIPT'S COLUMNS. `is_final` — not `final` — is the live column name,\n * and only final rows are ever written (D6: an interim is a caption and a\n * caption is never persisted).\n */\nconst SEGMENT_COLUMNS = \"id,meeting_id,identity,speaker,text,started_at,is_final,metadata\";\n\n/** What the meeting decided. `kind` is a three-value CHECK constraint (D5). */\nconst NOTE_COLUMNS = \"id,meeting_id,text,kind,assignee_user_id,created_at,metadata\";\n\n/**\n * WHO WAS THERE. The row survives the room, which is the whole point: an\n * attendance list that only exists while LiveKit holds the room is not a record\n * of anything (MRI-D2).\n */\nconst ATTENDEE_COLUMNS =\n \"id,meeting_id,identity,participant_user_id,display_name,avatar_url,role,\" +\n \"admission_state,is_agent,joined_at,left_at\";\n\ntype Row = Record<string, unknown>;\n\nfunction text(row: Row, key: string): string | null {\n const value = row[key];\n return typeof value === \"string\" && value.length > 0 ? value : null;\n}\n\nfunction requireText(row: Row, key: string, operation: string): string {\n const value = text(row, key);\n if (value === null) {\n throw invalidResponse(operation, `the row is missing \"${key}\"`);\n }\n return value;\n}\n\nfunction bool(row: Row, key: string, fallback: boolean): boolean {\n const value = row[key];\n return typeof value === \"boolean\" ? value : fallback;\n}\n\nfunction stringArray(row: Row, key: string): readonly string[] {\n const value = row[key];\n if (!Array.isArray(value)) return [];\n return value.filter((entry): entry is string => typeof entry === \"string\");\n}\n\nconst CALL_STATES: readonly CallState[] = [\n \"idle\",\n \"dialing\",\n \"ringing\",\n \"connecting\",\n \"active\",\n \"declined\",\n \"missed\",\n \"busy\",\n \"cancelled\",\n \"ended\",\n \"failed\",\n];\n\nfunction callState(value: string | null): CallState {\n return CALL_STATES.includes(value as CallState) ? (value as CallState) : \"failed\";\n}\n\nexport interface CreateCallInviteInput {\n readonly roomName: RoomName;\n readonly mode: CallMode;\n readonly callerUserId: UserId;\n readonly callerName: string;\n readonly callerAvatarUrl: string | null;\n readonly calleeUserIds: readonly UserId[];\n readonly organizationId: OrganizationId;\n readonly conversationId: string | null;\n readonly expiresAt: string;\n}\n\nexport interface CreateMeetingInput {\n readonly organizationId: OrganizationId;\n readonly hostUserId: UserId;\n readonly title: string;\n readonly kind: MeetingKind;\n readonly scheduledFor?: string | null;\n readonly scheduledDurationMinutes?: number | null;\n readonly lobbyEnabled?: boolean;\n readonly recordingPolicy?: RecordingPolicy;\n readonly aiEnabled?: boolean;\n /** Reuse a durable slug (a recurring meeting keeps ONE link — R3). */\n readonly slug?: string | undefined;\n}\n\nexport interface MeetRepository {\n readonly schema: string;\n readonly tables: typeof TABLES;\n projectInvite(row: Row): CallInvite;\n projectMeeting(row: Row): MeetingRecord;\n createCallInvite(input: CreateCallInviteInput): Promise<CallInvite>;\n settleCallInvite(id: CallId, state: CallState, declineMessage: string | null): Promise<CallInvite>;\n pendingInvites(userId: UserId): Promise<readonly CallInvite[]>;\n getOrCreateMeeting(input: CreateMeetingInput): Promise<MeetingRecord>;\n meetingBySlug(slug: string): Promise<MeetingRecord>;\n meeting(id: MeetingId): Promise<MeetingRecord>;\n /** Keyset paged, `(scheduled_for, id)`. */\n listMeetings(args: {\n organizationId: OrganizationId;\n limit?: number;\n before?: { scheduledFor: string; id: MeetingId } | null;\n }): Promise<{ readonly items: readonly MeetingRecord[]; readonly hasMore: boolean }>;\n admit(args: {\n meetingId: MeetingId;\n identity: string;\n admitted: boolean;\n byUserId: UserId;\n }): Promise<void>;\n setLock(meetingId: MeetingId, locked: boolean, byUserId: UserId): Promise<MeetingRecord>;\n endMeeting(meetingId: MeetingId, byUserId: UserId): Promise<MeetingRecord>;\n projectSegment(row: Row): TranscriptSegment;\n projectNote(row: Row): MeetingNote;\n /** One `meet_recordings` row, however it arrived (row or room packet). */\n projectRecording(row: Row): RecordingRecord;\n /** One durable `meet_participants` row — attendance, and the lobby queue. */\n projectAttendee(row: Row): MeetingAttendee;\n projectAttendee(row: Row): MeetingAttendee;\n /**\n * WHO ATTENDED, oldest arrival first. Everyone the meeting ever admitted —\n * including the note-taker, which is a labelled participant and never a hidden\n * listener (R4) — so the record can say who was in the room AND that it was\n * transcribed.\n */\n attendees(meetingId: MeetingId): Promise<readonly MeetingAttendee[]>;\n /**\n * THE DURABLE TRANSCRIPT (D16). Final rows only — the table holds nothing\n * else — oldest first, capped so a four-hour meeting cannot hand a surface\n * fifty thousand rows in one read.\n */\n transcript(meetingId: MeetingId, limit?: number): Promise<readonly TranscriptSegment[]>;\n /** Live notes, decisions, action items and the wrap-up summary, oldest first. */\n notes(meetingId: MeetingId): Promise<readonly MeetingNote[]>;\n /** R5: consent is RECORDED, not assumed. One row per participant per recording. */\n recordConsent(args: {\n meetingId: MeetingId;\n identity: string;\n acknowledgedAt: string;\n }): Promise<void>;\n recordings(meetingId: MeetingId): Promise<readonly RecordingRecord[]>;\n /** Meet wave 3: every recording of the reader's own meetings, newest first. */\n myRecordings(args?: { includeArchived?: boolean; limit?: number }): Promise<readonly LibraryRecording[]>;\n /** Meet wave 3: search the reader's own meetings. */\n searchMeetings(query: string, limit?: number): Promise<readonly MeetingSearchHit[]>;\n /** Meet wave 3: name a recording (`null` = back to the meeting's title and date). */\n renameRecording(recordingId: string, title: string | null): Promise<void>;\n /** Meet wave 3: archive (soft delete) or restore a recording. Never a purge. */\n setRecordingArchived(recordingId: string, archived: boolean): Promise<void>;\n\n /* ── MEET WAVE 1 — management (0.8) ── */\n scheduleMeeting(input: ScheduleMeetingInput): Promise<MeetingRecord>;\n /** `expectedVersion` from the row you edited; a stale one is a `conflict`. */\n updateMeeting(\n meetingId: MeetingId,\n changes: MeetingChanges,\n options?: { expectedVersion?: number | null; byUserId?: UserId | null },\n ): Promise<MeetingRecord>;\n cancelMeeting(meetingId: MeetingId, reason: string | null, byUserId?: UserId | null): Promise<MeetingRecord>;\n archiveMeeting(meetingId: MeetingId, byUserId?: UserId | null): Promise<MeetingRecord>;\n restoreMeeting(meetingId: MeetingId, byUserId?: UserId | null): Promise<MeetingRecord>;\n setOccurrence(args: {\n meetingId: MeetingId;\n originalStart: string;\n action: \"cancel\" | \"move\" | \"restore\";\n newStart?: string | null;\n newDurationMinutes?: number | null;\n reason?: string | null;\n byUserId?: UserId | null;\n }): Promise<OccurrenceOverride>;\n meetingOccurrences(\n meetingId: MeetingId,\n range: { from: string; to: string; limit?: number },\n ): Promise<readonly MeetingOccurrence[]>;\n /** The Upcoming list: every occurrence the reader may see. `organizationId` FILTERS; RLS decides. */\n occurrencesBetween(range: {\n from: string;\n to: string;\n organizationId?: OrganizationId | null;\n limit?: number;\n }): Promise<readonly UpcomingOccurrence[]>;\n invitees(meetingId: MeetingId): Promise<readonly MeetingInvitee[]>;\n addInvitees(meetingId: MeetingId, people: readonly InviteeInput[], byUserId?: UserId | null): Promise<readonly MeetingInvitee[]>;\n setInviteeRole(inviteeId: string, role: InviteeRole, byUserId?: UserId | null): Promise<MeetingInvitee>;\n removeInvitee(inviteeId: string, byUserId?: UserId | null): Promise<MeetingInvitee>;\n respond(meetingId: MeetingId, answer: RsvpAnswer, note?: string | null): Promise<MeetingInvitee>;\n invitationByToken(secret: string): Promise<RsvpInvitation>;\n respondByToken(secret: string, answer: RsvpAnswer, note?: string | null): Promise<RsvpInvitation>;\n projectInvitee(row: Row): MeetingInvitee;\n}\n\nexport interface ScheduleMeetingInput {\n readonly organizationId: OrganizationId;\n readonly hostUserId: UserId;\n readonly title: string;\n readonly scheduledFor: string | null;\n /** IANA zone, e.g. `America/Los_Angeles`. The wall-clock time a series keeps across DST. */\n readonly timeZone: string;\n /** Omit to use the person's `meet.default_duration_minutes`. */\n readonly durationMinutes?: number | null | undefined;\n readonly agenda?: string | null | undefined;\n /** RRULE subset: FREQ=DAILY|WEEKLY|MONTHLY, INTERVAL, BYDAY, BYMONTHDAY, COUNT, UNTIL. */\n readonly recurrenceRule?: string | null | undefined;\n readonly settings?: MeetingSettings | undefined;\n}\n\nexport interface RepositoryOptions {\n /**\n * Any Supabase client. Deliberately the SHALLOW public shape — pass the\n * `SupabaseClient<Database>` you already have, with no cast. See the header.\n */\n client: MessagingSupabaseClient;\n /** Resolve a session; used to retry ONCE across the sign-in gap. */\n session?: (() => Promise<unknown>) | undefined;\n}\n\n/**\n * 🚨 THE PROJECTIONS ARE MODULE-LEVEL AND EXPORTED, DELIBERATELY (MRI-A12).\n *\n * A durable Meet row reaches a client on one of two transports: as a\n * `meet_notes` / `meet_transcript_segments` row over Postgres Changes, which\n * needs a Supabase session and an org grant, or as a `matrx.meet.*` packet on\n * the LiveKit data plane, which needs only the room token — and is therefore the\n * ONLY one a session-less guest can receive (MRI-A10 settled that `anon` never\n * gets a grant on an org-scoped table).\n *\n * Both carry the same row. If each transport projected it with its own function,\n * a guest and a member would render the same meeting differently the first time\n * the two drifted. So there is one function per row shape, it takes no client,\n * and `core/room-events.ts` calls exactly these.\n */\nexport function projectSegment(row: Row): TranscriptSegment {\n const operation = \"meet.projectSegment\";\n const id = requireText(row, \"id\", operation);\n return {\n id,\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n identity: asParticipantIdentity(text(row, \"identity\") ?? \"unknown\"),\n // A nameless line is a line nobody can act on. The identity is a worse\n // name than a real one and a far better one than an empty string.\n speaker: text(row, \"speaker\") ?? text(row, \"identity\") ?? \"Someone\",\n text: text(row, \"text\") ?? \"\",\n startedAt: text(row, \"started_at\") ?? new Date(0).toISOString(),\n // The table holds finals only; a row that somehow says otherwise is still\n // a durable record and is rendered as one.\n final: bool(row, \"is_final\", true),\n source: \"record\",\n // The worker publishes the caption under THIS row's id (`lk.segment_id` =\n // the durable segment id), which is what lets a record replace the exact\n // caption it supersedes instead of doubling the line (D16).\n captionId: id,\n };\n}\n\nexport function projectNote(row: Row): MeetingNote {\n const operation = \"meet.projectNote\";\n const kind = text(row, \"kind\");\n const rawMetadata = row[\"metadata\"];\n const metadata: Record<string, unknown> =\n typeof rawMetadata === \"object\" && rawMetadata !== null && !Array.isArray(rawMetadata)\n ? (rawMetadata as Record<string, unknown>)\n : {};\n const assignee = metadata[\"assignee\"];\n const assigneeRow: Record<string, unknown> =\n typeof assignee === \"object\" && assignee !== null && !Array.isArray(assignee)\n ? (assignee as Record<string, unknown>)\n : {};\n const windowValue = metadata[\"window\"];\n const windowRow: Record<string, unknown> =\n typeof windowValue === \"object\" && windowValue !== null && !Array.isArray(windowValue)\n ? (windowValue as Record<string, unknown>)\n : {};\n const assigneeUserId = text(row, \"assignee_user_id\");\n const displayName = assigneeRow[\"display_name\"];\n return {\n id: requireText(row, \"id\", operation),\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n text: (text(row, \"text\") ?? \"\").trim(),\n createdAt: text(row, \"created_at\") ?? new Date().toISOString(),\n // An unknown kind is a NOTE, never dropped: a row the database accepted\n // is a row a person wrote down, whatever a future migration calls it.\n kind:\n kind === \"decision\" || kind === \"action-item\" ? (kind as MeetingNote[\"kind\"]) : \"note\",\n assigneeUserId: assigneeUserId === null ? null : asUserId(assigneeUserId),\n // D18: a guest never gets an `assignee_user_id` (the FK targets\n // `auth.users`), so their name lives in the metadata and is read here —\n // an action item whose owner has no name is an action item nobody owns.\n assigneeDisplayName:\n typeof displayName === \"string\" && displayName.length > 0 ? displayName : null,\n role: metadata[\"role\"] === \"summary\" ? \"summary\" : null,\n window: typeof windowRow[\"index\"] === \"number\" ? windowRow[\"index\"] : null,\n // D20. `superseded_by` is in `NOTE_PUBLIC_METADATA_KEYS` server-side, so a\n // session-less guest's room-borne copy carries it too — otherwise the guest\n // would be the one lane still reading a decision twice.\n supersededBy:\n typeof metadata[\"superseded_by\"] === \"string\" && metadata[\"superseded_by\"].length > 0\n ? (metadata[\"superseded_by\"] as string)\n : null,\n // THE DATABASE ROW. `core/room-events.ts` marks its copy of the same row\n // `\"room\"`, and the store's precedence rule reads this field (MRI-A12).\n source: \"record\",\n };\n}\n\n\n\n/* ─────────────────────────────── MEET WAVE 1 — management projections (0.8) */\n\nconst RSVP_STATES: readonly RsvpState[] = [\"needs_action\", \"accepted\", \"declined\", \"tentative\"];\nconst OCCURRENCE_STATES: readonly OccurrenceState[] = [\"scheduled\", \"moved\", \"cancelled\"];\n\nfunction rsvpState(value: string | null): RsvpState {\n return RSVP_STATES.includes(value as RsvpState) ? (value as RsvpState) : \"needs_action\";\n}\n\nfunction num(row: Row, key: string): number | null {\n const value = row[key];\n return typeof value === \"number\" ? value : null;\n}\n\n/** A database timestamp as ISO text. PostgREST sends strings; a test double may send Dates. */\nfunction when(row: Row, key: string): string | null {\n const value = row[key];\n if (value instanceof Date) return value.toISOString();\n return text(row, key);\n}\n\nexport function projectInvitee(row: Row): MeetingInvitee {\n const operation = \"meet.projectInvitee\";\n const userId = text(row, \"invitee_user_id\");\n return {\n id: requireText(row, \"id\", operation),\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n userId: userId === null ? null : asUserId(userId),\n email: text(row, \"email\"),\n displayName: text(row, \"display_name\"),\n role: text(row, \"role\") === \"cohost\" ? \"cohost\" : \"invitee\",\n rsvpState: rsvpState(text(row, \"rsvp_state\")),\n respondedAt: when(row, \"responded_at\"),\n rsvpNote: text(row, \"rsvp_note\"),\n lastSentSequence: num(row, \"last_sent_sequence\"),\n lastSentAt: when(row, \"last_sent_at\"),\n };\n}\n\nexport function projectOccurrence(row: Row): MeetingOccurrence {\n const operation = \"meet.projectOccurrence\";\n const state = text(row, \"state\");\n return {\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n originalStart: when(row, \"original_start\") ?? requireText(row, \"original_start\", operation),\n occurrenceStart: when(row, \"occurrence_start\") ?? requireText(row, \"occurrence_start\", operation),\n durationMinutes: num(row, \"duration_minutes\"),\n // An unknown state is shown as scheduled, never dropped: the row is real.\n state: OCCURRENCE_STATES.includes(state as OccurrenceState) ? (state as OccurrenceState) : \"scheduled\",\n sequence: num(row, \"sequence\") ?? 0,\n };\n}\n\nexport function projectUpcoming(row: Row): UpcomingOccurrence {\n const operation = \"meet.projectUpcoming\";\n const kind = text(row, \"kind\");\n const myRole = text(row, \"my_role\");\n const myRsvp = text(row, \"my_rsvp\");\n return {\n ...projectOccurrence(row),\n organizationId: asOrganizationId(requireText(row, \"organization_id\", operation)),\n title: text(row, \"title\") ?? \"Meeting\",\n slug: requireText(row, \"slug\", operation),\n kind: kind === \"scheduled\" || kind === \"recurring\" ? (kind as MeetingKind) : \"instant\",\n hostUserId: asUserId(requireText(row, \"host_user_id\", operation)),\n timeZone: text(row, \"time_zone\") ?? \"UTC\",\n meetingCancelled: bool(row, \"meeting_cancelled\", false),\n myRsvp: myRsvp === null ? null : rsvpState(myRsvp),\n myRole: myRole === \"host\" || myRole === \"cohost\" || myRole === \"invitee\" ? myRole : null,\n };\n}\n\nexport function projectOverride(row: Row): OccurrenceOverride {\n const operation = \"meet.projectOverride\";\n return {\n id: requireText(row, \"id\", operation),\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n originalStart: when(row, \"original_start\") ?? requireText(row, \"original_start\", operation),\n state: text(row, \"state\") === \"moved\" ? \"moved\" : \"cancelled\",\n newStart: when(row, \"new_start\"),\n newDurationMinutes: num(row, \"new_duration_minutes\"),\n reason: text(row, \"reason\"),\n calendarSequence: num(row, \"calendar_sequence\") ?? 0,\n deletedAt: when(row, \"deleted_at\"),\n };\n}\n\n/** The jsonb the RSVP doors return, typed. A body that is neither shape is refused loudly. */\nexport function projectRsvpInvitation(body: unknown): RsvpInvitation {\n const operation = \"meet.projectRsvpInvitation\";\n if (typeof body !== \"object\" || body === null) {\n throw invalidResponse(operation, \"the RSVP door returned no object\");\n }\n const row = body as Row;\n if (row[\"ok\"] !== true) {\n return {\n ok: false,\n message: text(row, \"message\") ?? \"This invitation link is no longer valid — ask the host to send it again.\",\n };\n }\n const meeting = (row[\"meeting\"] ?? {}) as Row;\n const invitee = (row[\"invitee\"] ?? {}) as Row;\n return {\n ok: true,\n meeting: {\n title: text(meeting, \"title\") ?? \"Meeting\",\n slug: requireText(meeting, \"slug\", operation),\n scheduledFor: when(meeting, \"scheduled_for\"),\n durationMinutes: num(meeting, \"duration_minutes\"),\n timeZone: text(meeting, \"time_zone\") ?? \"UTC\",\n agenda: text(meeting, \"agenda\"),\n recurrenceRule: text(meeting, \"recurrence_rule\"),\n cancelledAt: when(meeting, \"cancelled_at\"),\n cancellationReason: text(meeting, \"cancellation_reason\"),\n endedAt: when(meeting, \"ended_at\"),\n },\n invitee: {\n displayName: text(invitee, \"display_name\"),\n email: text(invitee, \"email\"),\n rsvpState: rsvpState(text(invitee, \"rsvp_state\")),\n respondedAt: when(invitee, \"responded_at\"),\n },\n };\n}\n\n/** Settings → the door's snake_case object, carrying ONLY what was set. */\nexport function settingsPatch(settings: MeetingSettings): Record<string, unknown> {\n const patch: Record<string, unknown> = {};\n if (settings.lobbyEnabled !== undefined) patch[\"lobby_enabled\"] = settings.lobbyEnabled;\n if (settings.recordingPolicy !== undefined) patch[\"recording_policy\"] = settings.recordingPolicy;\n if (settings.aiEnabled !== undefined) patch[\"ai_enabled\"] = settings.aiEnabled;\n if (settings.joinBeforeHost !== undefined) patch[\"join_before_host\"] = settings.joinBeforeHost;\n return patch;\n}\n\n/**\n * A partial edit → the `meet_update_meeting` patch. `undefined` = leave alone,\n * `null` = clear — the difference a JSON patch exists to carry.\n */\nexport function changesPatch(changes: MeetingChanges): Record<string, unknown> {\n const patch = settingsPatch(changes);\n if (changes.title !== undefined) patch[\"title\"] = changes.title;\n if (changes.agenda !== undefined) patch[\"agenda\"] = changes.agenda;\n if (changes.timeZone !== undefined) patch[\"time_zone\"] = changes.timeZone;\n if (changes.scheduledFor !== undefined) patch[\"scheduled_for\"] = changes.scheduledFor;\n if (changes.scheduledDurationMinutes !== undefined) {\n patch[\"scheduled_duration_minutes\"] = changes.scheduledDurationMinutes;\n }\n if (changes.recurrenceRule !== undefined) patch[\"recurrence_rule\"] = changes.recurrenceRule;\n return patch;\n}\n\nexport function createMeetRepository(options: RepositoryOptions): MeetRepository {\n // THE ONE NARROWING, in-package. Everything below works against the rich\n // internal contract; no consumer ever has to satisfy it.\n const db = (options.client as SupabaseLike).schema(MEET_SCHEMA);\n\n /**\n * 🚨 A `RETURNS void` RPC RESOLVES TO `null`, AND THAT IS SUCCESS.\n *\n * `guard` below treats a null `data` as an invalid response, which is right\n * for every RPC that returns a row and CATASTROPHIC for one that returns\n * nothing: `communication.meet_admit_participant` and `meet_record_consent`\n * are both `RETURNS void`, so from the day this package shipped, admitting\n * somebody from the lobby and recording consent BOTH performed their write\n * and then threw \"the database returned no row\" on the way back — the write\n * landed, the client believed it failed, the broadcast that tells the guest\n * never went out, and the guest sat in the waiting room forever. Found in a\n * browser (MRI-A11); the RPC return types are pinned in `VOID_RPCS` below so\n * a future void RPC cannot be wired to the wrong guard by accident.\n */\n async function guardVoid(\n operation: string,\n run: () => PromiseLike<{ data: unknown; error: { message: string; code?: string } | null }>,\n ): Promise<void> {\n let response = await run();\n if (response.error !== null) {\n const normalized = normalizeMeetError(response.error, operation);\n if (normalized.code === \"session-unavailable\" && options.session !== undefined) {\n await options.session();\n response = await run();\n }\n if (response.error !== null) throw normalizeMeetError(response.error, operation);\n }\n // No row is expected and none is read. The absence of an error IS the\n // result — anything else would be inventing a postcondition the database\n // never promised.\n }\n\n async function guard<T>(operation: string, run: () => PromiseLike<{ data: T | null; error: { message: string; code?: string } | null }>): Promise<T> {\n let response = await run();\n if (response.error !== null) {\n const normalized = normalizeMeetError(response.error, operation);\n // ONE retry, and only for the sign-in gap. A permission denial is NEVER\n // retried — retrying one is how a request storm is built.\n if (normalized.code === \"session-unavailable\" && options.session !== undefined) {\n await options.session();\n response = await run();\n }\n if (response.error !== null) throw normalizeMeetError(response.error, operation);\n }\n if (response.data === null) {\n throw invalidResponse(operation, \"the database returned no row\");\n }\n return response.data;\n }\n\n function projectInvite(row: Row): CallInvite {\n const operation = \"meet.projectInvite\";\n const mode = text(row, \"mode\");\n return {\n id: asCallId(requireText(row, \"id\", operation)),\n organizationId: asOrganizationId(requireText(row, \"organization_id\", operation)),\n roomName: asRoomName(requireText(row, \"room_name\", operation)),\n mode: mode === \"video\" ? \"video\" : \"audio\",\n callerUserId: asUserId(requireText(row, \"caller_user_id\", operation)),\n callerName: text(row, \"caller_name\") ?? \"Someone\",\n callerAvatarUrl: text(row, \"caller_avatar_url\"),\n calleeUserIds: stringArray(row, \"callee_ids\").map(asUserId),\n conversationId: text(row, \"conversation_id\"),\n createdAt: requireText(row, \"created_at\", operation),\n expiresAt: text(row, \"expires_at\") ?? requireText(row, \"created_at\", operation),\n state: callState(text(row, \"state\")),\n declineMessage: text(row, \"decline_message\"),\n };\n }\n\n function projectMeeting(row: Row): MeetingRecord {\n const operation = \"meet.projectMeeting\";\n const kind = text(row, \"kind\");\n const policy = text(row, \"recording_policy\");\n const duration = row[\"scheduled_duration_minutes\"];\n const metadata = row[\"metadata\"];\n return {\n id: asMeetingId(requireText(row, \"id\", operation)),\n organizationId: asOrganizationId(requireText(row, \"organization_id\", operation)),\n roomName: asRoomName(requireText(row, \"room_name\", operation)),\n slug: requireText(row, \"slug\", operation),\n title: text(row, \"title\") ?? \"Meeting\",\n kind: kind === \"scheduled\" || kind === \"recurring\" ? (kind as MeetingKind) : \"instant\",\n hostUserId: asUserId(requireText(row, \"host_user_id\", operation)),\n scheduledFor: text(row, \"scheduled_for\"),\n scheduledDurationMinutes: typeof duration === \"number\" ? duration : null,\n startedAt: text(row, \"started_at\"),\n endedAt: text(row, \"ended_at\"),\n locked: bool(row, \"locked\", false),\n lobbyEnabled: bool(row, \"lobby_enabled\", true),\n recordingPolicy:\n policy === \"disabled\" || policy === \"always-on\"\n ? (policy as RecordingPolicy)\n : \"host-controlled\",\n aiEnabled: bool(row, \"ai_enabled\", true),\n metadata:\n typeof metadata === \"object\" && metadata !== null && !Array.isArray(metadata)\n ? (metadata as JsonObject)\n : {},\n timeZone: text(row, \"time_zone\") ?? \"UTC\",\n agenda: text(row, \"agenda\"),\n recurrenceRule: text(row, \"recurrence_rule\"),\n joinBeforeHost: bool(row, \"join_before_host\", true),\n cancelledAt: text(row, \"cancelled_at\"),\n cancellationReason: text(row, \"cancellation_reason\"),\n deletedAt: text(row, \"deleted_at\"),\n calendarSequence: typeof row[\"calendar_sequence\"] === \"number\" ? row[\"calendar_sequence\"] : 0,\n version: typeof row[\"version\"] === \"number\" ? row[\"version\"] : 1,\n };\n }\n\n function projectRecording(row: Row): RecordingRecord {\n const operation = \"meet.projectRecording\";\n const state = text(row, \"state\");\n const known: readonly RecordingState[] = [\n \"idle\",\n \"starting\",\n \"recording\",\n \"stopping\",\n \"processing\",\n \"available\",\n \"expired\",\n \"failed\",\n ];\n return {\n id: requireText(row, \"id\", operation),\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n state: known.includes(state as RecordingState) ? (state as RecordingState) : \"failed\",\n startedAt: text(row, \"started_at\"),\n endedAt: text(row, \"ended_at\"),\n startedBy: text(row, \"started_by\") === null ? null : asUserId(text(row, \"started_by\") as string),\n // A PLATFORM file id, never a provider URL (R3). A recording that only\n // exists as a LiveKit URL is orphaned the day the room is garbage\n // collected, which is the whole reason this column is not `url`.\n fileId: text(row, \"file_id\"),\n failureReason: text(row, \"failure_reason\"),\n retention: projectRecordingRetention(row[\"metadata\"]),\n };\n }\n\n function projectRecordingRetention(value: unknown): RecordingRetention | null {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return null;\n const retention = (value as Record<string, unknown>)[\"retention\"];\n if (typeof retention !== \"object\" || retention === null || Array.isArray(retention)) return null;\n const row = retention as Record<string, unknown>;\n const phase = row[\"phase\"];\n const operationId = row[\"operation_id\"];\n const policyId = row[\"policy_id\"];\n const policyUpdatedAt = row[\"policy_updated_at\"];\n const dueAt = row[\"due_at\"];\n const expiredAt = row[\"expired_at\"];\n if (\n (phase !== \"warning\" && phase !== \"expired\") ||\n typeof operationId !== \"string\" ||\n typeof policyId !== \"string\" ||\n typeof policyUpdatedAt !== \"string\" ||\n typeof dueAt !== \"string\" ||\n (expiredAt !== null && typeof expiredAt !== \"string\")\n ) return null;\n return { operationId, policyId, policyUpdatedAt, phase, dueAt, expiredAt };\n }\n\n function projectAttendee(row: Row): MeetingAttendee {\n const operation = \"meet.projectAttendee\";\n const role = text(row, \"role\");\n const admission = text(row, \"admission_state\");\n const known: readonly ParticipantRole[] = [\"host\", \"cohost\", \"participant\", \"guest\"];\n const states: readonly AdmissionState[] = [\"knocking\", \"admitted\", \"denied\", \"removed\"];\n const userId = text(row, \"participant_user_id\");\n const identity = requireText(row, \"identity\", operation);\n return {\n id: requireText(row, \"id\", operation),\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n identity: asParticipantIdentity(identity),\n // A nameless attendee is a row nobody can read. The identity is a worse\n // name than a real one and an infinitely better one than a blank.\n displayName: text(row, \"display_name\") ?? identity,\n avatarUrl: text(row, \"avatar_url\"),\n userId: userId === null ? null : asUserId(userId),\n role: known.includes(role as ParticipantRole) ? (role as ParticipantRole) : \"participant\",\n admissionState: states.includes(admission as AdmissionState)\n ? (admission as AdmissionState)\n : \"admitted\",\n isAgent: bool(row, \"is_agent\", false),\n joinedAt: text(row, \"joined_at\"),\n leftAt: text(row, \"left_at\"),\n };\n }\n\n function requireOrg(organizationId: OrganizationId, operation: string): void {\n if (typeof organizationId !== \"string\" || organizationId.length === 0) {\n throw new MeetError(\n \"misconfigured\",\n `${operation}: no organization_id`,\n \"Every meet write carries an explicit organization_id (R5). The package refuses the \" +\n \"write rather than letting an unscoped row reach the database.\",\n );\n }\n }\n\n return {\n schema: MEET_SCHEMA,\n tables: TABLES,\n projectInvite,\n projectMeeting,\n projectSegment,\n projectNote,\n projectRecording,\n projectAttendee,\n projectInvitee,\n\n async scheduleMeeting(input) {\n requireOrg(input.organizationId, \"meet.scheduleMeeting\");\n const row = await guard<Row>(\"meet.scheduleMeeting\", () =>\n db.rpc<Row>(RPCS.scheduleMeeting, {\n p_organization_id: input.organizationId,\n p_host_user_id: input.hostUserId,\n p_title: input.title,\n p_scheduled_for: input.scheduledFor,\n p_time_zone: input.timeZone,\n p_duration_minutes: input.durationMinutes ?? null,\n p_agenda: input.agenda ?? null,\n p_recurrence_rule: input.recurrenceRule ?? null,\n p_settings: settingsPatch(input.settings ?? {}),\n }),\n );\n return projectMeeting(row);\n },\n\n async updateMeeting(meetingId, changes, options = {}) {\n const row = await guard<Row>(\"meet.updateMeeting\", () =>\n db.rpc<Row>(RPCS.updateMeeting, {\n p_meeting_id: meetingId,\n p_changes: changesPatch(changes),\n p_expected_version: options.expectedVersion ?? null,\n p_by_user_id: options.byUserId ?? null,\n }),\n );\n return projectMeeting(row);\n },\n\n async cancelMeeting(meetingId, reason, byUserId = null) {\n const row = await guard<Row>(\"meet.cancelMeeting\", () =>\n db.rpc<Row>(RPCS.cancelMeeting, {\n p_meeting_id: meetingId,\n p_reason: reason,\n p_by_user_id: byUserId,\n }),\n );\n return projectMeeting(row);\n },\n\n async archiveMeeting(meetingId, byUserId = null) {\n const row = await guard<Row>(\"meet.archiveMeeting\", () =>\n db.rpc<Row>(RPCS.archiveMeeting, { p_meeting_id: meetingId, p_by_user_id: byUserId }),\n );\n return projectMeeting(row);\n },\n\n async restoreMeeting(meetingId, byUserId = null) {\n const row = await guard<Row>(\"meet.restoreMeeting\", () =>\n db.rpc<Row>(RPCS.restoreMeeting, { p_meeting_id: meetingId, p_by_user_id: byUserId }),\n );\n return projectMeeting(row);\n },\n\n async setOccurrence(args) {\n const row = await guard<Row>(\"meet.setOccurrence\", () =>\n db.rpc<Row>(RPCS.setOccurrence, {\n p_meeting_id: args.meetingId,\n p_original_start: args.originalStart,\n p_action: args.action,\n p_new_start: args.newStart ?? null,\n p_new_duration_minutes: args.newDurationMinutes ?? null,\n p_reason: args.reason ?? null,\n p_by_user_id: args.byUserId ?? null,\n }),\n );\n return projectOverride(row);\n },\n\n async meetingOccurrences(meetingId, { from, to, limit = 200 }) {\n const rows = await guard<Row[]>(\"meet.meetingOccurrences\", () =>\n db.rpc<Row[]>(RPCS.meetingOccurrences, {\n p_meeting_id: meetingId,\n p_from: from,\n p_to: to,\n p_limit: limit,\n }),\n );\n return rows.map(projectOccurrence);\n },\n\n async occurrencesBetween({ from, to, organizationId = null, limit = 500 }) {\n const rows = await guard<Row[]>(\"meet.occurrencesBetween\", () =>\n db.rpc<Row[]>(RPCS.occurrencesBetween, {\n p_from: from,\n p_to: to,\n p_organization_id: organizationId,\n p_limit: limit,\n }),\n );\n return rows.map(projectUpcoming);\n },\n\n async invitees(meetingId) {\n const response = await db\n .from<Row>(TABLES.invitees)\n .select(INVITEE_COLUMNS)\n .eq(\"meeting_id\", meetingId)\n .is(\"deleted_at\", null)\n .order(\"created_at\", { ascending: true })\n .order(\"id\", { ascending: true });\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.invitees\");\n return (response.data ?? []).map(projectInvitee);\n },\n\n async addInvitees(meetingId, people, byUserId = null) {\n const rows = await guard<Row[]>(\"meet.addInvitees\", () =>\n db.rpc<Row[]>(RPCS.addInvitees, {\n p_meeting_id: meetingId,\n p_invitees: people.map((person) => ({\n ...(person.userId !== undefined ? { user_id: person.userId } : {}),\n ...(person.email !== undefined ? { email: person.email } : {}),\n ...(person.displayName !== undefined ? { display_name: person.displayName } : {}),\n ...(person.role !== undefined ? { role: person.role } : {}),\n })),\n p_by_user_id: byUserId,\n }),\n );\n return rows.map(projectInvitee);\n },\n\n async setInviteeRole(inviteeId, role, byUserId = null) {\n const row = await guard<Row>(\"meet.setInviteeRole\", () =>\n db.rpc<Row>(RPCS.setInviteeRole, {\n p_invitee_id: inviteeId,\n p_role: role,\n p_by_user_id: byUserId,\n }),\n );\n return projectInvitee(row);\n },\n\n async removeInvitee(inviteeId, byUserId = null) {\n const row = await guard<Row>(\"meet.removeInvitee\", () =>\n db.rpc<Row>(RPCS.removeInvitee, { p_invitee_id: inviteeId, p_by_user_id: byUserId }),\n );\n return projectInvitee(row);\n },\n\n async respond(meetingId, answer, note = null) {\n const row = await guard<Row>(\"meet.respond\", () =>\n db.rpc<Row>(RPCS.respond, {\n p_meeting_id: meetingId,\n p_response: answer,\n p_note: note,\n p_by_user_id: null,\n }),\n );\n return projectInvitee(row);\n },\n\n async invitationByToken(secret) {\n const body = await guard<unknown>(\"meet.invitationByToken\", () =>\n db.rpc<unknown>(RPCS.invitationByToken, { p_secret: secret }),\n );\n return projectRsvpInvitation(body);\n },\n\n async respondByToken(secret, answer, note = null) {\n const body = await guard<unknown>(\"meet.respondByToken\", () =>\n db.rpc<unknown>(RPCS.respondByToken, {\n p_secret: secret,\n p_response: answer,\n p_note: note,\n }),\n );\n return projectRsvpInvitation(body);\n },\n\n async attendees(meetingId) {\n const response = await db\n .from<Row>(TABLES.participants)\n .select(ATTENDEE_COLUMNS)\n .eq(\"meeting_id\", meetingId)\n .order(\"joined_at\", { ascending: true })\n .order(\"id\", { ascending: true });\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.attendees\");\n return (response.data ?? []).map(projectAttendee);\n },\n\n async createCallInvite(input) {\n requireOrg(input.organizationId, \"meet.createCallInvite\");\n const row = await guard<Row>(\"meet.createCallInvite\", () =>\n db.rpc<Row>(RPCS.createCallInvite, {\n p_room_name: input.roomName,\n p_mode: input.mode,\n p_caller_user_id: input.callerUserId,\n p_caller_name: input.callerName,\n p_caller_avatar_url: input.callerAvatarUrl,\n p_callee_ids: input.calleeUserIds,\n p_organization_id: input.organizationId,\n p_conversation_id: input.conversationId,\n p_expires_at: input.expiresAt,\n }),\n );\n return projectInvite(row);\n },\n\n async settleCallInvite(id, state, declineMessage) {\n const row = await guard<Row>(\"meet.settleCallInvite\", () =>\n db.rpc<Row>(RPCS.settleCallInvite, {\n p_invite_id: id,\n p_state: state,\n p_decline_message: declineMessage,\n }),\n );\n return projectInvite(row);\n },\n\n async pendingInvites(userId) {\n const rows = await guard<Row[]>(\"meet.pendingInvites\", () =>\n db.rpc<Row[]>(RPCS.pendingCallInvites, { p_user_id: userId }),\n );\n return rows.map(projectInvite);\n },\n\n async getOrCreateMeeting(input) {\n requireOrg(input.organizationId, \"meet.getOrCreateMeeting\");\n const row = await guard<Row>(\"meet.getOrCreateMeeting\", () =>\n db.rpc<Row>(RPCS.getOrCreateMeeting, {\n p_organization_id: input.organizationId,\n p_host_user_id: input.hostUserId,\n p_title: input.title,\n p_kind: input.kind,\n p_scheduled_for: input.scheduledFor ?? null,\n p_scheduled_duration_minutes: input.scheduledDurationMinutes ?? null,\n p_lobby_enabled: input.lobbyEnabled ?? true,\n p_recording_policy: input.recordingPolicy ?? \"host-controlled\",\n p_ai_enabled: input.aiEnabled ?? true,\n p_slug: input.slug ?? null,\n }),\n );\n return projectMeeting(row);\n },\n\n async meetingBySlug(slug) {\n // A DURABLE LINK RESOLVES BEFORE, DURING, AND AFTER (R3). This RPC is not\n // filtered by `ended_at is null` on purpose: a link that dies the moment\n // the meeting ends breaks every \"here are the notes\" follow-up.\n const row = await guard<Row>(\"meet.meetingBySlug\", () =>\n db.rpc<Row>(RPCS.meetingBySlug, { p_slug: slug }),\n );\n return projectMeeting(row);\n },\n\n async meeting(id) {\n const response = await db\n .from<Row>(TABLES.meetings)\n .select(MEETING_COLUMNS)\n .eq(\"id\", id)\n .single();\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.meeting\");\n if (response.data === null) throw invalidResponse(\"meet.meeting\", \"no such meeting\");\n return projectMeeting(response.data);\n },\n\n async listMeetings({ organizationId, limit = 25, before = null }) {\n requireOrg(organizationId, \"meet.listMeetings\");\n let query = db\n .from<Row>(TABLES.meetings)\n .select(MEETING_COLUMNS)\n .eq(\"organization_id\", organizationId)\n .order(\"scheduled_for\", { ascending: false })\n .order(\"id\", { ascending: false })\n // ASK FOR ONE MORE THAN THE PAGE, so `hasMore` is a fact rather than a\n // guess from \"we got a full page\".\n .limit(limit + 1);\n if (before !== null) {\n query = query.or(\n `scheduled_for.lt.${before.scheduledFor},and(scheduled_for.eq.${before.scheduledFor},id.lt.${before.id})`,\n );\n }\n const response = await query;\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.listMeetings\");\n const rows = response.data ?? [];\n return {\n items: rows.slice(0, limit).map(projectMeeting),\n hasMore: rows.length > limit,\n };\n },\n\n async admit({ meetingId, identity, admitted, byUserId }) {\n await guardVoid(\"meet.admit\", () =>\n db.rpc<Row>(RPCS.admit, {\n p_meeting_id: meetingId,\n p_identity: identity,\n p_admitted: admitted,\n p_by_user_id: byUserId,\n }),\n );\n },\n\n async setLock(meetingId, locked, byUserId) {\n const row = await guard<Row>(\"meet.setLock\", () =>\n db.rpc<Row>(RPCS.setLock, {\n p_meeting_id: meetingId,\n p_locked: locked,\n p_by_user_id: byUserId,\n }),\n );\n return projectMeeting(row);\n },\n\n async endMeeting(meetingId, byUserId) {\n const row = await guard<Row>(\"meet.endMeeting\", () =>\n db.rpc<Row>(RPCS.endMeeting, {\n p_meeting_id: meetingId,\n p_by_user_id: byUserId,\n }),\n );\n return projectMeeting(row);\n },\n\n async transcript(meetingId, limit = 1000) {\n const response = await db\n .from<Row>(TABLES.transcripts)\n .select(SEGMENT_COLUMNS)\n .eq(\"meeting_id\", meetingId)\n .order(\"started_at\", { ascending: true })\n .order(\"id\", { ascending: true })\n .limit(limit);\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.transcript\");\n return (response.data ?? []).map(projectSegment);\n },\n\n async notes(meetingId) {\n const response = await db\n .from<Row>(TABLES.notes)\n .select(NOTE_COLUMNS)\n .eq(\"meeting_id\", meetingId)\n .order(\"created_at\", { ascending: true })\n .order(\"id\", { ascending: true });\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.notes\");\n return (response.data ?? []).map(projectNote);\n },\n\n async recordConsent({ meetingId, identity, acknowledgedAt }) {\n await guardVoid(\"meet.recordConsent\", () =>\n db.rpc<Row>(RPCS.recordConsent, {\n p_meeting_id: meetingId,\n p_identity: identity,\n p_acknowledged_at: acknowledgedAt,\n }),\n );\n },\n\n async recordings(meetingId) {\n const response = await db\n .from<Row>(TABLES.recordings)\n .select(RECORDING_COLUMNS)\n .eq(\"meeting_id\", meetingId)\n // Meet wave 3: an archived recording is off the record as well as the library.\n .is(\"deleted_at\", null)\n .order(\"started_at\", { ascending: false });\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.recordings\");\n return (response.data ?? []).map(projectRecording);\n },\n\n async myRecordings({ includeArchived = false, limit = 200 } = {}) {\n const rows = await guard<Row[]>(\"meet.myRecordings\", () =>\n db.rpc<Row[]>(RPCS.myRecordings, { p_include_archived: includeArchived, p_limit: limit }),\n );\n return rows.map(projectLibraryRecording);\n },\n\n async searchMeetings(query, limit = 60) {\n if (query.trim().length === 0) return [];\n const rows = await guard<Row[]>(\"meet.searchMeetings\", () =>\n db.rpc<Row[]>(RPCS.search, { p_query: query, p_limit: limit }),\n );\n return rows.map(projectSearchHit);\n },\n\n async renameRecording(recordingId, title) {\n const clean = title === null ? null : title.trim().slice(0, 200) || null;\n const response = await db\n .from<Row>(TABLES.recordings)\n .update({ title: clean })\n .eq(\"id\", recordingId)\n .select(\"id\");\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.renameRecording\");\n if ((response.data ?? []).length === 0) {\n throw normalizeMeetError(\n { message: \"permission denied: only the meeting's host or an editor can rename it\", code: \"42501\" },\n \"meet.renameRecording\",\n );\n }\n },\n\n async setRecordingArchived(recordingId, archived) {\n const response = await db\n .from<Row>(TABLES.recordings)\n .update({ deleted_at: archived ? new Date().toISOString() : null })\n .eq(\"id\", recordingId)\n .select(\"id\");\n if (response.error !== null) throw normalizeMeetError(response.error, \"meet.setRecordingArchived\");\n if ((response.data ?? []).length === 0) {\n throw normalizeMeetError(\n { message: \"permission denied: only the meeting's host or an editor can archive it\", code: \"42501\" },\n \"meet.setRecordingArchived\",\n );\n }\n },\n };\n}\n\n/** One row of the recordings library (`meet_my_recordings`). */\nexport interface LibraryRecording {\n readonly id: string;\n readonly meetingId: MeetingId;\n readonly meetingTitle: string;\n readonly meetingSlug: string;\n /** The reader's strongest role on the meeting. */\n readonly role: \"host\" | \"cohost\" | \"invitee\" | \"attendee\";\n readonly state: RecordingState;\n /** A name a host gave it; null = show the meeting title. */\n readonly title: string | null;\n readonly fileId: string | null;\n readonly startedAt: string | null;\n readonly endedAt: string | null;\n readonly durationMs: number | null;\n readonly sizeBytes: number | null;\n readonly failureReason: string | null;\n readonly archivedAt: string | null;\n readonly organizationId: OrganizationId;\n}\n\nconst LIBRARY_STATES: readonly RecordingState[] = [\n \"idle\",\n \"starting\",\n \"recording\",\n \"stopping\",\n \"processing\",\n \"available\",\n \"expired\",\n \"failed\",\n];\n\nexport function projectLibraryRecording(row: Row): LibraryRecording {\n const operation = \"meet.projectLibraryRecording\";\n const state = text(row, \"state\");\n const role = text(row, \"my_role\");\n return {\n id: requireText(row, \"recording_id\", operation),\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n meetingTitle: text(row, \"meeting_title\") ?? \"Meeting\",\n meetingSlug: requireText(row, \"meeting_slug\", operation),\n role: role === \"host\" || role === \"cohost\" || role === \"invitee\" ? role : \"attendee\",\n state: LIBRARY_STATES.includes(state as RecordingState) ? (state as RecordingState) : \"failed\",\n title: text(row, \"recording_title\"),\n fileId: text(row, \"file_id\"),\n startedAt: text(row, \"started_at\"),\n endedAt: text(row, \"ended_at\"),\n durationMs: num(row, \"duration_ms\"),\n sizeBytes: num(row, \"size_bytes\"),\n failureReason: text(row, \"failure_reason\"),\n archivedAt: text(row, \"deleted_at\"),\n organizationId: asOrganizationId(requireText(row, \"organization_id\", operation)),\n };\n}\n\n/** Where a search hit was found. */\nexport type MeetingSearchSource =\n | \"title\"\n | \"summary\"\n | \"decision\"\n | \"action_item\"\n | \"note\"\n | \"transcript\";\n\n/** One hit from `meet_search`. `snippet` marks matched words with ⟦ ⟧. */\nexport interface MeetingSearchHit {\n readonly meetingId: MeetingId;\n readonly meetingTitle: string;\n readonly meetingSlug: string;\n readonly meetingAt: string | null;\n readonly source: MeetingSearchSource;\n /** The note or transcript segment id (the meeting id for a title hit). */\n readonly refId: string;\n readonly speaker: string | null;\n readonly snippet: string;\n /** When it was said / written. */\n readonly at: string | null;\n readonly rank: number;\n}\n\nconst SEARCH_SOURCES: readonly MeetingSearchSource[] = [\n \"title\",\n \"summary\",\n \"decision\",\n \"action_item\",\n \"note\",\n \"transcript\",\n];\n\nexport function projectSearchHit(row: Row): MeetingSearchHit {\n const operation = \"meet.projectSearchHit\";\n const source = text(row, \"source\");\n return {\n meetingId: asMeetingId(requireText(row, \"meeting_id\", operation)),\n meetingTitle: text(row, \"meeting_title\") ?? \"Meeting\",\n meetingSlug: requireText(row, \"meeting_slug\", operation),\n meetingAt: text(row, \"meeting_at\"),\n source: SEARCH_SOURCES.includes(source as MeetingSearchSource)\n ? (source as MeetingSearchSource)\n : \"note\",\n refId: requireText(row, \"ref_id\", operation),\n speaker: text(row, \"speaker\"),\n snippet: text(row, \"snippet\") ?? \"\",\n at: text(row, \"said_at\"),\n rank: num(row, \"rank\") ?? 0,\n };\n}\n\n/** A snippet split into plain and matched runs, for highlighting without HTML. */\nexport function snippetRuns(snippet: string): readonly { readonly text: string; readonly hit: boolean }[] {\n const runs: { text: string; hit: boolean }[] = [];\n const pattern = /⟦([^⟧]*)⟧/g;\n let last = 0;\n for (const match of snippet.matchAll(pattern)) {\n const start = match.index ?? 0;\n if (start > last) runs.push({ text: snippet.slice(last, start), hit: false });\n runs.push({ text: match[1] ?? \"\", hit: true });\n last = start + match[0].length;\n }\n if (last < snippet.length) runs.push({ text: snippet.slice(last), hit: false });\n return runs;\n}\n","/**\n * WHO IS ACTING — read from the session, never from a prop (DD-240).\n *\n * THE CLASS THIS CLOSES. Through 0.5.x `<MeetProvider userId>` took the acting\n * user's id from the host, and every host had the same one source for it: a\n * copy held in its own client state (matrx-frontend's Redux `selectUserId`).\n * That copy is written once, when the app boots, and nothing rewrites it when\n * the domain-wide auth cookie rotates to a different account, when the person\n * signs out in another tab, or when a refresh returns a different subject. The\n * package then went on issuing user-scoped reads on behalf of somebody the\n * session is no longer:\n *\n * `communication.meet_pending_call_invites(p_user_id => <the stale copy>)`\n * → 42501 at HTTP 403, \"meet: the acting user (4cf62e4e…) is not the\n * authenticated user\"\n *\n * Measured on production 2026-09-14 (register DD-238/DD-240): the two rows came\n * from tabs 8.8 h and 32.9 h old, and the id in the argument named a DIFFERENT\n * account from the one the error sink recorded for the same row. The database\n * was right both times. The defect was that a user id can be handed in at all.\n *\n * So there is ONE source now, and it is the client's own session. The same\n * client that mints the JWT on every PostgREST request answers \"who is this?\",\n * so the id in the argument and the id in the token cannot disagree — not\n * because they are kept in step, but because they are the same fact read once.\n *\n * WHAT THIS MODULE IS. A tiny observable over `client.auth`: the current acting\n * user id, a subscription that fires when it changes, and a `resolving` state\n * that is honest about the moment before the first `getSession()` answers.\n *\n * - It is `resolving` until the first read lands. Nothing user-scoped is\n * issued in that window, which is what a page-load race used to spend\n * issuing reads as a user the tab could not prove it was.\n * - `snapshot()` returns THE SAME REFERENCE until the acting user moves\n * (FEATURE.md rule 7b — a `useSyncExternalStore` source that returns a fresh\n * object per call is \"Maximum update depth exceeded\", not a warning).\n * - It NEVER refuses anything on its own authority. It reports who the session\n * says you are; the database remains the only thing that decides what that\n * is allowed to read.\n * - A client with no `auth` at all is a real, named failure with a remedy —\n * never a silent fall back to \"nobody\" (FEATURE.md rule 7).\n *\n * THE CLIENT BOUNDARY STAYS SHALLOW (0.2.1, `repository.ts`'s header). The\n * public prop type is still `MessagingSupabaseClient`, which does not describe\n * `auth` at all — so this module narrows to its own minimal `AuthLike` in ONE\n * place, exactly as `createMeetRepository` narrows to `SupabaseLike`. A real\n * `SupabaseClient` satisfying `AuthLike` is proven at compile time in\n * `supabase-shape.test.ts`.\n */\n\nimport type { MessagingSupabaseClient } from \"@ai-matrx/messaging\";\nimport { asUserId, type UserId } from \"./types\";\n\n/** What a session looks like to this module. Nothing else is read from it. */\nexport interface AuthSessionLike {\n readonly user?: { readonly id?: string | null } | null | undefined;\n}\n\nexport interface AuthSubscriptionLike {\n readonly data: { readonly subscription: { unsubscribe(): void } };\n}\n\n/**\n * The subset of `client.auth` this package uses — the INTERNAL contract, never\n * a public prop type.\n */\nexport interface AuthLike {\n getSession(): PromiseLike<{\n data: { session?: AuthSessionLike | null | undefined };\n }>;\n onAuthStateChange(\n callback: (event: string, session: AuthSessionLike | null) => void,\n ): AuthSubscriptionLike;\n}\n\nexport interface SessionIdentitySnapshot {\n /**\n * `resolving` until the first `getSession()` answers. A user-scoped read\n * issued in this window would be issued on behalf of a guess.\n */\n readonly state: \"resolving\" | \"resolved\";\n /** Who the session says is acting, or `null` for nobody. */\n readonly userId: UserId | null;\n}\n\nexport interface SessionIdentity {\n /** Stable reference until the acting user actually changes (rule 7b). */\n snapshot(): SessionIdentitySnapshot;\n subscribe(listener: () => void): () => void;\n dispose(): void;\n}\n\nexport interface SessionIdentityOptions {\n readonly client: MessagingSupabaseClient;\n readonly onDiagnostic?:\n | ((event: {\n level: \"info\" | \"warn\" | \"error\";\n message: string;\n remedy?: string | undefined;\n }) => void)\n | undefined;\n}\n\nconst RESOLVING: SessionIdentitySnapshot = Object.freeze({\n state: \"resolving\" as const,\n userId: null,\n});\n\n/** The snapshot every server render sees: nobody is acting on a server. */\nexport const SERVER_SESSION_IDENTITY: SessionIdentitySnapshot = RESOLVING;\n\n/**\n * The one narrowing. A client whose `auth` is missing or not shaped like an\n * auth client is a real failure — we say so, and stay `resolved` with nobody\n * acting, which makes the provider inert rather than wrong.\n */\nexport function authOf(client: MessagingSupabaseClient): AuthLike | null {\n const candidate = (client as unknown as { auth?: unknown }).auth;\n if (candidate === null || typeof candidate !== \"object\") return null;\n const auth = candidate as Partial<AuthLike>;\n if (typeof auth.getSession !== \"function\") return null;\n if (typeof auth.onAuthStateChange !== \"function\") return null;\n return auth as AuthLike;\n}\n\nfunction userIdOf(session: AuthSessionLike | null | undefined): UserId | null {\n const id = session?.user?.id;\n return typeof id === \"string\" && id.length > 0 ? asUserId(id) : null;\n}\n\nexport function createSessionIdentity(options: SessionIdentityOptions): SessionIdentity {\n const { client, onDiagnostic } = options;\n const listeners = new Set<() => void>();\n let current: SessionIdentitySnapshot = RESOLVING;\n let disposed = false;\n\n const publish = (state: \"resolving\" | \"resolved\", userId: UserId | null): void => {\n if (disposed) return;\n // SAME REFERENCE until the fact moves (rule 7b).\n if (current.state === state && current.userId === userId) return;\n current = Object.freeze({ state, userId });\n for (const listener of [...listeners]) listener();\n };\n\n const auth = authOf(client);\n if (auth === null) {\n onDiagnostic?.({\n level: \"error\",\n message:\n \"Meet cannot tell who is signed in: the Supabase client it was given has no auth \" +\n \"session source.\",\n remedy:\n \"Pass your app's browser Supabase client to <MeetProvider client={...}> — the same \" +\n \"client it signs in with. Meet reads the acting user from that client's session; \" +\n \"there is no prop for a user id, on purpose.\",\n });\n current = Object.freeze({ state: \"resolved\" as const, userId: null });\n return {\n snapshot: () => current,\n subscribe: (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n dispose: () => {\n disposed = true;\n listeners.clear();\n },\n };\n }\n\n // The first read. `getSession()` awaits auth-js's own initialization and its\n // single-flighted refresh, so this is the same answer the next PostgREST\n // request's JWT will carry.\n void (async () => {\n try {\n const result = await auth.getSession();\n publish(\"resolved\", userIdOf(result?.data?.session));\n } catch (error: unknown) {\n onDiagnostic?.({\n level: \"warn\",\n message: `Meet could not read the signed-in session: ${String(\n (error as Error)?.message ?? error,\n )}`,\n remedy:\n \"Calls and meetings stay unavailable on this device until the session can be read. \" +\n \"Reload the page; if it persists, sign in again.\",\n });\n publish(\"resolved\", null);\n }\n })();\n\n // …and every change after it. A sign-out, an account switch, and a refresh\n // that returns a different subject all land here.\n const subscription = auth.onAuthStateChange((_event, session) => {\n publish(\"resolved\", userIdOf(session));\n });\n\n return {\n snapshot: () => current,\n subscribe: (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n dispose: () => {\n disposed = true;\n listeners.clear();\n try {\n subscription.data.subscription.unsubscribe();\n } catch {\n // An already-torn-down subscription is not a failure worth a sentence.\n }\n },\n };\n}\n","/**\n * THE PLATFORM'S OWN VOICE IN THE ROOM — and the ONLY live feed a guest has.\n *\n * 🚨 **Why this file exists.** Everything durable a meeting produces — a live\n * note, a decision, an action item, the note-taker's state, the ending — lands\n * in `communication.meet_*`, and a signed-in member learns about it over\n * Postgres Changes. A GUEST cannot: `anon` holds no SELECT grant on\n * `meet_notes`, `meet_transcript_segments` or `meet_participants`, and MRI-A10\n * settled that widening it is forbidden, because those are org-scoped tables and\n * a meeting link is not org membership. A guest's authority is the ROOM TOKEN.\n * So the platform publishes the same rows into the room, where the token is the\n * authorization, and this file turns those packets into exactly the same store\n * calls the database path makes.\n *\n * Three rules hold it together:\n *\n * 1. **Same row, same projection, same reducer.** A `matrx.meet.note` packet\n * carries a `meet_notes` row and is projected by `projectNote` — the very\n * function the Postgres Changes handler uses — then handed to\n * `store.upsertNote`. A guest and a member therefore converge on one code\n * path rather than on two implementations that agree until they don't.\n * 2. **Keyed by the row id, so both copies are one thing.** A member receives\n * every note TWICE. They render once because the id is the row's id on both\n * transports, and where the two could disagree the database wins\n * (`store.upsertNote`'s precedence rule, D16).\n * 3. **`matrx.meet.*` is the server's namespace and nothing else's.** LiveKit\n * does not validate a data packet's sender, so any participant could publish\n * any bytes under any topic. What makes these trustworthy is that publishing\n * them requires a `roomAdmin` grant, which only the server's own control\n * token carries — a participant token cannot claim it. The in-room control\n * plane participants DO publish (hand, reaction, chat) lives under `mx.*`\n * and is handled separately, precisely so the two can never be confused.\n */\n\nimport { projectNote } from \"./repository\";\nimport type { MeetStore, RoomChatMessage } from \"./store\";\nimport {\n asMeetingId,\n asParticipantIdentity,\n type JsonObject,\n type MeetingRecord,\n type ParticipantRole,\n type RecordingState,\n type UserId,\n type WrapUpAnnouncement,\n} from \"./types\";\n\n/** Pinned against `RecordingState`; an unknown word is dropped, never shown. */\nconst RECORDING_STATES: readonly RecordingState[] = [\n \"idle\",\n \"starting\",\n \"recording\",\n \"stopping\",\n \"processing\",\n \"available\",\n \"expired\",\n \"failed\",\n];\n\n/**\n * The server's namespace. Pinned against `aidream/services/meet/livekit.py`'s\n * `ROOM_EVENT_PREFIX` — a rename on either side must break a named test here.\n */\nexport const ROOM_EVENT_PREFIX = \"matrx.meet.\";\n\nexport const ROOM_EVENTS = {\n /** One durable `meet_notes` row was written. Payload `{ note: <row> }`. */\n note: \"matrx.meet.note\",\n /** `meet_meetings.metadata.note_taker` changed. Payload `{ meeting_id, note_taker }`. */\n noteTaker: \"matrx.meet.note_taker\",\n /** A wrap-up pass finished. Payload `{ meeting_id, note_ids, segment_count }`. */\n wrapUp: \"matrx.meet.wrap_up\",\n /** The meeting ended for everyone. Payload `{ meeting_id, ended_at, trigger }`. */\n ended: \"matrx.meet.ended\",\n /**\n * A `meet_recordings` row changed state. Payload\n * `{ meeting_id, recording: { id, state, started_by } }`.\n *\n * 🚨 THIS IS THE ONLY WAY A GUEST LEARNS A RECORDING IS RUNNING. PreJoin\n * promises every joiner an indicator, and `anon` holds no SELECT grant on\n * `meet_recordings` (MRI-A10 settled that widening it is forbidden), so\n * without this packet the promise was a sentence with nothing behind it: on\n * production 2026-09-09 the guest lane showed no indicator at all while the\n * host recorded (MRI-C8).\n */\n recording: \"matrx.meet.recording\",\n /**\n * A chat message to everyone was SAVED (Meet wave 2). Payload\n * `{ message: { id, meeting_id, sender_identity, sender_name, body, created_at } }`.\n */\n chat: \"matrx.meet.chat\",\n /**\n * A host or co-host acted (Meet wave 2). Payload `{ meeting_id, kind, … }`:\n * `muted {source, by}` · `ask-unmute {by}` · `removed {by}` — addressed to the\n * person concerned; `lower-hands {identities: [...] | \"*\"}` · `role {identity,\n * role}` — to everyone.\n */\n moderation: \"matrx.meet.moderation\",\n} as const;\n\nexport type RoomEventTopic = (typeof ROOM_EVENTS)[keyof typeof ROOM_EVENTS];\n\nexport function isRoomEventTopic(topic: string): boolean {\n return topic.startsWith(ROOM_EVENT_PREFIX);\n}\n\ntype Payload = Record<string, unknown>;\n\nfunction object(value: unknown): Payload | null {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Payload)\n : null;\n}\n\nfunction text(value: unknown): string | null {\n return typeof value === \"string\" && value.length > 0 ? value : null;\n}\n\n/**\n * What happened to one packet. Returned rather than logged from inside, so the\n * room engine can report a drop with its own diagnostic channel and a test can\n * assert on it — a packet that is silently ignored is indistinguishable from\n * one that never arrived, which is the failure this whole item is about.\n */\nexport interface RoomEventOutcome {\n readonly handled: boolean;\n /** Present when `handled` is false. Says what was wrong, in a sentence. */\n readonly ignored?: string;\n}\n\nconst HANDLED: RoomEventOutcome = { handled: true };\n\nfunction ignored(reason: string): RoomEventOutcome {\n return { handled: false, ignored: reason };\n}\n\nexport interface ApplyRoomEventArgs {\n readonly store: MeetStore;\n readonly topic: string;\n /** The packet's already-parsed JSON body. */\n readonly payload: unknown;\n readonly now?: (() => number) | undefined;\n}\n\n/**\n * Apply one `matrx.meet.*` packet to the store. Never throws.\n *\n * A malformed packet is DROPPED with a reason, never partially applied: half a\n * note on a guest's screen is worse than no note, because the guest cannot tell\n * which half they are missing.\n */\nexport function applyRoomEvent(args: ApplyRoomEventArgs): RoomEventOutcome {\n const { store, topic } = args;\n if (!isRoomEventTopic(topic)) {\n return ignored(`${topic} is not a Meet room event`);\n }\n const payload = object(args.payload);\n if (payload === null) {\n return ignored(`${topic} carried no object payload`);\n }\n const now = args.now ?? (() => Date.now());\n\n switch (topic) {\n case ROOM_EVENTS.note:\n return applyNote(store, payload);\n case ROOM_EVENTS.noteTaker:\n return applyNoteTaker(store, payload);\n case ROOM_EVENTS.wrapUp:\n return applyWrapUp(store, payload, now);\n case ROOM_EVENTS.ended:\n return applyEnded(store, payload);\n case ROOM_EVENTS.recording:\n return applyRecording(store, payload);\n case ROOM_EVENTS.chat:\n return applyChat(store, payload);\n case ROOM_EVENTS.moderation:\n return applyModeration(store, payload, now);\n default:\n // A NEWER SERVER, not a bug. Ignoring an unknown event under our own\n // prefix is what lets the platform ship a new one without breaking every\n // client that has not been redeployed.\n return ignored(`${topic} is not known to this version of @ai-matrx/meet`);\n }\n}\n\nfunction applyNote(store: MeetStore, payload: Payload): RoomEventOutcome {\n const row = object(payload[\"note\"]);\n if (row === null) return ignored(\"a note event with no `note` row\");\n if (text(row[\"id\"]) === null || text(row[\"meeting_id\"]) === null) {\n // Without the row id there is no dedupe key, and appending a note that can\n // never be matched to its database copy is exactly the double-render bug.\n return ignored(\"a note row with no id or meeting_id\");\n }\n const meeting = store.snapshot().meeting;\n if (meeting !== null && row[\"meeting_id\"] !== meeting.id) {\n return ignored(\"a note for a different meeting than this room is showing\");\n }\n try {\n // THE SAME PROJECTION THE DATABASE PATH USES — one definition of what a\n // note row means — re-stamped as the room copy so the store's precedence\n // rule can keep the database's word on top.\n store.upsertNote({ ...projectNote(row), source: \"room\" });\n } catch (error) {\n return ignored(`a note row this client could not read: ${String(error)}`);\n }\n return HANDLED;\n}\n\nfunction applyNoteTaker(store: MeetStore, payload: Payload): RoomEventOutcome {\n const noteTaker = object(payload[\"note_taker\"]);\n if (noteTaker === null) return ignored(\"a note-taker event with no state\");\n const meeting = store.snapshot().meeting;\n if (meeting === null) {\n // An ad-hoc call room has no meeting record to hang the state on, and\n // there is no note-taker in one. Stated, not silent.\n return ignored(\"a note-taker state with no meeting record to attach it to\");\n }\n const meetingId = text(payload[\"meeting_id\"]);\n if (meetingId !== null && meetingId !== meeting.id) {\n return ignored(\"a note-taker state for a different meeting\");\n }\n // MERGED, NOT REPLACED. The packet carries only the `note_taker` object — the\n // two keys a surface renders — because the rest of the row names people and\n // organizations a guest is not authorized to learn. Everything else on the\n // meeting record stays exactly as the join backfill left it.\n const next: MeetingRecord = {\n ...meeting,\n metadata: { ...meeting.metadata, note_taker: noteTaker as JsonObject },\n };\n store.patch({ meeting: next });\n return HANDLED;\n}\n\nfunction applyWrapUp(\n store: MeetStore,\n payload: Payload,\n now: () => number,\n): RoomEventOutcome {\n const meetingId = text(payload[\"meeting_id\"]);\n if (meetingId === null) return ignored(\"a wrap-up event with no meeting id\");\n const meeting = store.snapshot().meeting;\n if (meeting !== null && meetingId !== meeting.id) {\n return ignored(\"a wrap-up for a different meeting\");\n }\n const rawIds = payload[\"note_ids\"];\n const noteIds = Array.isArray(rawIds)\n ? rawIds.filter((value): value is string => typeof value === \"string\")\n : [];\n const segmentCount = payload[\"segment_count\"];\n const announcement: WrapUpAnnouncement = {\n meetingId: asMeetingId(meetingId),\n noteIds,\n segmentCount: typeof segmentCount === \"number\" ? segmentCount : 0,\n at: new Date(now()).toISOString(),\n };\n store.announceWrapUp(announcement);\n return HANDLED;\n}\n\nfunction applyRecording(store: MeetStore, payload: Payload): RoomEventOutcome {\n const row = object(payload[\"recording\"]);\n if (row === null) return ignored(\"a recording event with no `recording` row\");\n const meetingId = text(payload[\"meeting_id\"]);\n const meeting = store.snapshot().meeting;\n if (meeting !== null && meetingId !== null && meetingId !== meeting.id) {\n return ignored(\"a recording state for a different meeting than this room is showing\");\n }\n const state = text(row[\"state\"]);\n if (state === null || !RECORDING_STATES.includes(state as RecordingState)) {\n // An UNKNOWN state is dropped rather than rendered: a recording indicator\n // that says a word nobody defined is worse than one that says nothing.\n return ignored(`a recording state this version does not know: ${String(row[\"state\"])}`);\n }\n const by = text(row[\"started_by\"]);\n // `\"room\"` — the durable row outranks this the moment a member's\n // subscription delivers it (D16, `store.setRecording`).\n store.setRecording(\n state as RecordingState,\n by === null ? null : (by as UserId),\n \"room\",\n text(row[\"id\"]),\n );\n return HANDLED;\n}\n\nfunction applyEnded(store: MeetStore, payload: Payload): RoomEventOutcome {\n const meetingId = text(payload[\"meeting_id\"]);\n const meeting = store.snapshot().meeting;\n if (meeting === null) return ignored(\"an ended event with no meeting record\");\n if (meetingId !== null && meetingId !== meeting.id) {\n return ignored(\"an ended event for a different meeting\");\n }\n // 🚨 THE LAST THING A GUEST HEARS. Ending a meeting deletes the LiveKit room,\n // so the server publishes this in the moment BEFORE the delete — and a client\n // that ignored it would keep saying the meeting is live while everyone is\n // disconnected. The `left` phase that follows says nothing about WHY.\n const endedAt = text(payload[\"ended_at\"]) ?? new Date().toISOString();\n if (meeting.endedAt === endedAt) return HANDLED;\n store.patch({ meeting: { ...meeting, endedAt } });\n return HANDLED;\n}\n\n/** One saved chat row as the room sees it. Shared with the history read. */\nexport function chatFromRow(row: Payload): RoomChatMessage | null {\n const id = text(row[\"id\"]);\n const identity = text(row[\"sender_identity\"]);\n const body = text(row[\"body\"]);\n if (id === null || identity === null || body === null) return null;\n return {\n id,\n identity: asParticipantIdentity(identity),\n displayName: text(row[\"sender_name\"]) ?? \"Participant\",\n text: body,\n at: text(row[\"created_at\"]) ?? new Date().toISOString(),\n // `false` only from a server whose chat table has not landed: the room heard\n // it, nobody will see it later — and the line says so.\n saved: row[\"saved\"] !== false,\n };\n}\n\nfunction applyChat(store: MeetStore, payload: Payload): RoomEventOutcome {\n const row = object(payload[\"message\"]);\n if (row === null) return ignored(\"a chat event with no `message` row\");\n const meeting = store.snapshot().meeting;\n if (meeting !== null && text(row[\"meeting_id\"]) !== null && row[\"meeting_id\"] !== meeting.id) {\n return ignored(\"a chat message for a different meeting\");\n }\n const message = chatFromRow(row);\n if (message === null) return ignored(\"a chat row with no id, sender or body\");\n store.addChat(message);\n return HANDLED;\n}\n\n/** Sentences for what a host did to THIS participant. */\nfunction moderationText(kind: string, payload: Payload): string | null {\n const by = text(payload[\"by\"]) ?? \"The host\";\n switch (kind) {\n case \"muted\": {\n const source = text(payload[\"source\"]) ?? \"microphone\";\n return source === \"microphone\"\n ? `${by} muted you.`\n : source === \"camera\"\n ? `${by} turned off your camera.`\n : `${by} stopped your screen share.`;\n }\n case \"ask-unmute\":\n return `${by} is asking you to unmute.`;\n case \"removed\":\n return `${by} removed you from this meeting.`;\n default:\n return null;\n }\n}\n\nfunction applyModeration(store: MeetStore, payload: Payload, now: () => number): RoomEventOutcome {\n const snapshot = store.snapshot();\n const meetingId = text(payload[\"meeting_id\"]);\n if (snapshot.meeting !== null && meetingId !== null && meetingId !== snapshot.meeting.id) {\n return ignored(\"a moderation event for a different meeting\");\n }\n const kind = text(payload[\"kind\"]);\n switch (kind) {\n case \"lower-hands\": {\n const raw = payload[\"identities\"];\n const everyone = raw === \"*\";\n const named = new Set(\n Array.isArray(raw) ? raw.filter((value): value is string => typeof value === \"string\") : [],\n );\n for (const participant of snapshot.participants) {\n if (participant.handRaised && (everyone || named.has(participant.identity))) {\n store.setHand(participant.identity, false);\n }\n }\n return HANDLED;\n }\n case \"role\": {\n const identity = text(payload[\"identity\"]);\n const role = text(payload[\"role\"]);\n if (identity === null || role === null || !ROLES.includes(role as ParticipantRole)) {\n return ignored(\"a role event with no identity or an unknown role\");\n }\n // THE SERVER CHANGED ITS OWN DECISION. The token's role was minted at join;\n // a co-host made or unmade, or a host handed over, must re-grant or\n // UN-grant this screen's powers now — `effectiveRole` takes the stronger of\n // token and roster, so a demotion that left the token alone would leave the\n // old host holding host controls the server refuses.\n if (identity === snapshot.localIdentity) {\n store.patch({\n grants: { ...snapshot.grants, role: role as ParticipantRole },\n moderationNotice: {\n kind: \"role\",\n text:\n role === \"host\"\n ? \"You are now the host.\"\n : role === \"cohost\"\n ? \"You are now a co-host.\"\n : \"You are no longer a co-host.\",\n at: now(),\n },\n });\n }\n return HANDLED;\n }\n case \"muted\":\n case \"ask-unmute\":\n case \"removed\": {\n const sentence = moderationText(kind, payload);\n if (sentence === null) return ignored(\"a moderation event with no sentence\");\n store.patch({ moderationNotice: { kind, text: sentence, at: now() } });\n return HANDLED;\n }\n default:\n return ignored(`a moderation kind this version does not know: ${String(kind)}`);\n }\n}\n\nconst ROLES: readonly ParticipantRole[] = [\"host\", \"cohost\", \"participant\", \"guest\"];\n","/**\n * THE NOTE-TAKER, AS A SURFACE MUST RENDER IT.\n *\n * 🚨 **THE PACKAGE NEVER GUESSES WHAT THE AGENT IS DOING.** Two facts decide\n * everything here and both come from outside this client: the meeting row's\n * `metadata.note_taker` (written by the server with a CAS, MRI-A2/D9) and\n * whether the agent participant is actually in the LiveKit room. A spinner —\n * \"starting…\" held open by a client-side timer — is the exact lie this file\n * exists to prevent: it survives a worker that never came, a dispatch nobody\n * claimed, and a job that died on a release.\n *\n * 🚨 **A REFUSAL IS RENDERED VERBATIM.** `/agent/start` answers a 503 whose body\n * carries `reason` and `remedy` written by the readiness gate (D7) — \"no worker\n * is registered under matrx-note-taker\", \"every worker is at capacity\",\n * \"the fleet is draining\". Those sentences are the truth about the system and\n * they reach the screen unedited. This package adds no sentence of its own on\n * top of one the server already wrote.\n *\n * The agent's identity is DETERMINISTIC — `agent:note_taker:<meeting_id>` (D9) —\n * which is what makes \"is it in the room\" answerable without a round trip, and\n * what makes a second note-taker impossible to mistake for the first.\n */\n\nimport type { JsonObject, MeetParticipant, MeetingRecord, NoteTakerState } from \"./types\";\n\n/** The one spelling of the agent's participant identity (D9). */\nexport const NOTE_TAKER_IDENTITY_PREFIX = \"agent:note_taker:\";\n\nexport function noteTakerIdentity(meetingId: string): string {\n return `${NOTE_TAKER_IDENTITY_PREFIX}${meetingId}`;\n}\n\n/**\n * The participant attribute the note-taker sets on itself so EVERY client —\n * including one that cannot read the token metadata — knows a notice is owed\n * (D10).\n */\nexport const CONSENT_NOTICE_ATTRIBUTE = \"matrx.agent.consent_notice\";\n\n/** Where the state lives on the meeting row. One spelling, one file. */\nexport const NOTE_TAKER_METADATA_KEY = \"note_taker\";\n\nconst STATES: readonly NoteTakerState[] = [\n \"absent\",\n \"joining\",\n \"transcribing\",\n \"handoff_pending\",\n \"ended\",\n];\n\n/** The server's refusal, as it wrote it. Never paraphrased. */\nexport interface NoteTakerRefusal {\n readonly reason: string;\n readonly remedy: string;\n readonly status: number;\n}\n\nexport interface NoteTakerStatus {\n readonly state: NoteTakerState;\n /** The server's own words for why it is in this state, when it gave any. */\n readonly detail: string | null;\n /** True when the agent participant is in the room RIGHT NOW. */\n readonly present: boolean;\n /** The last dispatch refusal, rendered verbatim. */\n readonly refusal: NoteTakerRefusal | null;\n}\n\nfunction readState(value: unknown): NoteTakerState | null {\n return typeof value === \"string\" && STATES.includes(value as NoteTakerState)\n ? (value as NoteTakerState)\n : null;\n}\n\n/** Is this participant the note-taker (or any agent that owes a notice, D10)? */\nexport function isNoteTaker(participant: MeetParticipant): boolean {\n return (\n participant.identity.startsWith(NOTE_TAKER_IDENTITY_PREFIX) ||\n participant.attributes[CONSENT_NOTICE_ATTRIBUTE] !== undefined ||\n participant.isAgent\n );\n}\n\n/** The agent participant in the room, if any. */\nexport function noteTakerParticipant(\n participants: readonly MeetParticipant[],\n): MeetParticipant | null {\n return participants.find(isNoteTaker) ?? null;\n}\n\n/** The exact deterministic actor whose room presence can corroborate the row. */\nfunction exactNoteTakerParticipant(\n meeting: MeetingRecord | null,\n participants: readonly MeetParticipant[],\n): MeetParticipant | null {\n if (meeting === null) return null;\n const identity = noteTakerIdentity(meeting.id);\n return participants.find((participant) => participant.identity === identity) ?? null;\n}\n\n/**\n * THE STATE, from the two facts that decide it.\n *\n * The durable row is the authority for work. Exact room presence corroborates\n * only a durable `transcribing` state; an arbitrary agent, a consent marker,\n * or a stale note-taker participant never proves speech capture.\n */\nexport function noteTakerStatus(args: {\n meeting: MeetingRecord | null;\n participants: readonly MeetParticipant[];\n refusal?: NoteTakerRefusal | null;\n}): NoteTakerStatus {\n const present = exactNoteTakerParticipant(args.meeting, args.participants) !== null;\n const raw = args.meeting?.metadata[NOTE_TAKER_METADATA_KEY];\n const row: JsonObject =\n typeof raw === \"object\" && raw !== null && !Array.isArray(raw) ? raw : {};\n const recorded = readState(row[\"state\"]);\n const detail = typeof row[\"reason\"] === \"string\" && row[\"reason\"].length > 0\n ? row[\"reason\"]\n : null;\n const refusal = args.refusal ?? null;\n\n if (recorded === null) {\n return { state: \"absent\", detail, present, refusal };\n }\n if (recorded === \"transcribing\" && !present) {\n return { state: \"handoff_pending\", detail, present, refusal };\n }\n return { state: recorded, detail, present, refusal };\n}\n\n/**\n * THE SENTENCE FOR EACH STATE. One place, so the room, the panel and any future\n * surface say the same true thing — and so a state can never render as a bare\n * enum name.\n */\nexport function noteTakerLabel(status: NoteTakerStatus): string {\n switch (status.state) {\n case \"joining\":\n return \"The note-taker is joining this meeting\";\n case \"transcribing\":\n return \"The note-taker is connected and listening for speech\";\n case \"handoff_pending\":\n return \"The note-taker's transcription is interrupted; reconnection is pending\";\n case \"ended\":\n return \"The note-taker has stopped\";\n case \"absent\":\n default:\n return status.present\n ? \"A meeting assistant is connected. Transcription is not confirmed\"\n : \"No note-taker is in this meeting\";\n }\n}\n","/**\n * THE MEDIA SEAM — the ONE interface the room engine talks to.\n *\n * D1/D2: LiveKit Cloud is the media infrastructure, hardcoded. This interface\n * is NOT a provider abstraction and is not here so a second SFU can be swapped\n * in — it exists for two reasons that are both about correctness:\n *\n * 1. **The engine must be provable without a browser.** Everything expensive in\n * a calling product (ring timeouts, reconnection, admission, escalation,\n * speaker tracking) is logic, and logic proven only through a real SFU is\n * logic that is never proven. `testing/fake-driver.ts` drives every one of\n * those paths in a node test.\n * 2. **The SDK stays out of the initial chunk.** `livekit-client` is reached\n * only through a dynamic `import()` inside the default driver, so importing\n * this package during SSR — or on a page with a call BUTTON but no call —\n * costs nothing and touches no browser API.\n *\n * The default implementation ships (`createLiveKitDriver`) and is what\n * `<MeetProvider>` uses when a host injects nothing (THE ALL-INCLUSIVE LAW).\n */\n\nimport type { ConnectionQuality } from \"./types\";\n\n/** A participant as the media layer sees them, before roles or profiles. */\nexport interface DriverParticipant {\n readonly identity: string;\n readonly name: string;\n /** Opaque JSON string the token minted for this participant. */\n readonly metadata: string | null;\n /**\n * The participant's LiveKit attributes. Unlike `metadata` these are set by\n * the participant itself at run time, which is how the note-taker announces\n * that a consent notice is owed (D10).\n */\n readonly attributes: Readonly<Record<string, string>>;\n readonly isLocal: boolean;\n readonly micEnabled: boolean;\n readonly cameraEnabled: boolean;\n readonly screenSharing: boolean;\n}\n\nexport type DriverConnectionState =\n | \"connecting\"\n | \"connected\"\n | \"reconnecting\"\n | \"disconnected\";\n\nexport type DriverTrackKind = \"camera\" | \"microphone\" | \"screen\";\n\n/**\n * ONE LIVE CAPTION off the `lk.transcription` text stream.\n *\n * `speakerIdentity` is `lk.transcribed_participant_identity` — WHO IS BEING\n * TRANSCRIBED, not who published the stream (the note-taker publishes every\n * one of them). The SFU-reported publisher identity below is independently\n * checked against the meeting's note-taker; captions remain hints and durable\n * segments remain the record (D16).\n */\nexport interface DriverTranscription {\n /** `lk.segment_id`. Interim and final share it; that is what makes replacement possible. */\n readonly segmentId: string;\n readonly speakerIdentity: string;\n /**\n * The LiveKit participant that opened this text stream. Unlike\n * `speakerIdentity`, this comes from the SFU and is the authority for who\n * published a caption.\n */\n readonly publisherIdentity: string;\n readonly text: string;\n /** `lk.transcription_final`. */\n readonly final: boolean;\n /** `lk.transcribed_track_id`, when the sender supplied it. */\n readonly trackId: string | null;\n readonly at: string;\n}\n\nexport interface RoomDriverHandlers {\n /** The FULL roster, every time. A delta protocol here drifts; a snapshot cannot. */\n participants(participants: readonly DriverParticipant[]): void;\n activeSpeakers(identities: readonly string[]): void;\n quality(identity: string, quality: ConnectionQuality): void;\n connectionState(state: DriverConnectionState): void;\n /** In-room data messages: hand raise, reactions, in-room chat, AI events. */\n data(topic: string, payload: string, fromIdentity: string | null): void;\n /** A live caption. Interim and final both arrive here (D16). */\n transcription(event: DriverTranscription): void;\n /** The room ended for this client. `reason` is shown to the user verbatim. */\n disconnected(reason: string | null): void;\n /**\n * The ROOM's metadata — set only by the server (`UpdateRoomMetadata`), and\n * delivered to every joiner ON JOIN, which is why the spotlight rides it: a\n * data packet reaches only the people already in the room. Called once after\n * connect and on every change. Optional so an older host driver still works.\n */\n roomMetadata?(metadata: string): void;\n}\n\n/** A camera background effect. `image` replaces the background with `imageUrl`. */\nexport type VideoEffect =\n | { readonly kind: \"none\" }\n | { readonly kind: \"blur\"; readonly radius?: number }\n | { readonly kind: \"image\"; readonly imageUrl: string };\n\n/** Microphone processing the browser applies before anything is sent. */\nexport interface AudioProcessing {\n readonly noiseSuppression: boolean;\n readonly echoCancellation: boolean;\n readonly autoGainControl: boolean;\n}\n\nexport interface MeetRoomDriver {\n connect(serverUrl: string, token: string): Promise<void>;\n disconnect(): Promise<void>;\n setMicrophoneEnabled(enabled: boolean): Promise<void>;\n setCameraEnabled(enabled: boolean): Promise<void>;\n setScreenShareEnabled(enabled: boolean): Promise<void>;\n /**\n * Reliable, topic-addressed data. The in-room control plane. `to` addresses\n * named identities only (a private chat message); absent = everyone.\n */\n publishData(topic: string, payload: string, to?: readonly string[]): Promise<void>;\n /**\n * Apply microphone processing to the live track and to every future one.\n * Optional: a driver without it makes the control ABSENT, never dead.\n */\n setAudioProcessing?(processing: AudioProcessing): Promise<void>;\n /**\n * Apply a background effect to the live camera and to every future one.\n * Rejects with a sentence when this browser cannot run it.\n */\n setVideoEffect?(effect: VideoEffect): Promise<void>;\n /** Whether this browser can run background effects at all. */\n supportsVideoEffects?(): boolean;\n /**\n * Attach a participant's track to a media element. Returns the detach\n * function — returning it (rather than exposing `detach`) is what makes a\n * leaked attachment impossible from the React side: the effect's cleanup IS\n * the return value.\n */\n attach(identity: string, kind: DriverTrackKind, element: HTMLMediaElement): () => void;\n /** The device the driver actually selected, so the UI never lies about it. */\n activeDevices(): Readonly<Record<\"audioinput\" | \"videoinput\" | \"audiooutput\", string | null>>;\n switchDevice(kind: \"audioinput\" | \"videoinput\" | \"audiooutput\", deviceId: string): Promise<void>;\n}\n\nexport type RoomDriverFactory = (\n handlers: RoomDriverHandlers,\n) => MeetRoomDriver | Promise<MeetRoomDriver>;\n\n/** Topics for the in-room control plane. One place, so senders cannot drift. */\nexport const DATA_TOPICS = {\n hand: \"mx.hand\",\n reaction: \"mx.reaction\",\n chat: \"mx.chat\",\n} as const;\n\n/**\n * 🚨 `mx.ai.note` and `mx.ai.transcript` WERE declared here and emitted by\n * nothing. They are gone (MRI-A12): the platform's own events are published by\n * the SERVER under `matrx.meet.*` — see `core/room-events.ts` — because a packet\n * a participant could publish is a packet a guest could forge, and these carry\n * durable rows. A participant topic for the same thing would be a second,\n * unauthenticated way to say it.\n */\n\nexport type DataTopic = (typeof DATA_TOPICS)[keyof typeof DATA_TOPICS];\n\n/**\n * THE LIVEKIT TRANSCRIPTION CONTRACT — not ours, so it is written down once\n * rather than spelled inline. The topic and these four attribute names are the\n * SDK's own (`lk.*`); the worker publishes to exactly them (MRI-A2) and a\n * rename on either side must break here, loudly, in one place.\n */\nexport const TRANSCRIPTION_TOPIC = \"lk.transcription\";\n\nexport const TRANSCRIPTION_ATTRIBUTES = {\n segmentId: \"lk.segment_id\",\n trackId: \"lk.transcribed_track_id\",\n final: \"lk.transcription_final\",\n /**\n * WHO IS BEING TRANSCRIBED. The LiveKit JS client reports the PUBLISHER of a\n * text stream, and the publisher is always the note-taker — so a caption\n * carries the speaker in this attribute and falls back to the publisher only\n * when it is absent (which attributes the line to the agent, visibly, rather\n * than to the wrong person, silently).\n */\n speakerIdentity: \"lk.transcribed_participant_identity\",\n} as const;\n","/**\n * THE ROOM ENGINE — the object a host mounts once and never reasons about.\n *\n * It owns every sequence a calling product gets wrong: ask for a token, connect,\n * project the roster, carry the in-room control plane, keep the phase honest\n * through a reconnect, and tear everything down exactly once. A consumer's job\n * is `engine.join(...)` and rendering a snapshot.\n *\n * THREE rules are structural here, not documented-and-hoped:\n *\n * 1. **The phase never lies.** `connecting` becomes `connected` only when the\n * driver says so, and any failure becomes `failed` WITH the remedy attached\n * to the snapshot. There is no path that leaves a spinner running forever —\n * the single most common complaint about every video product.\n * 2. **Role comes from the TOKEN, never from the client.** A participant's role\n * is read out of the server-minted metadata. A client that could decide it\n * was host could mute anyone; here the claim is unforgeable because the\n * server signed it.\n * 3. **Teardown is idempotent and total.** Leaving twice, or unmounting during\n * a connect, disconnects once and leaves no listener behind. The half-torn\n * room is what produces \"my camera light stays on after the call\".\n */\n\nimport {\n IDLE_TRACK,\n type LocalTrackState,\n unavailableFrom,\n} from \"./attendance\";\nimport { MeetError, normalizeDeviceError, normalizeMeetError } from \"./errors\";\nimport { applyRoomEvent, isRoomEventTopic, ROOM_EVENTS } from \"./room-events\";\nimport { displayNameFor } from \"./names\";\nimport { noteTakerIdentity } from \"./note-taker\";\nimport { captionSegment } from \"./transcript\";\nimport {\n DATA_TOPICS,\n type DriverParticipant,\n type MeetRoomDriver,\n type RoomDriverFactory,\n type RoomDriverHandlers,\n type VideoEffect,\n} from \"./room-driver\";\nimport { type MediaEffects, type MeetStore } from \"./store\";\nimport type { RoomToken, TokenClient } from \"./tokens\";\nimport {\n asParticipantIdentity,\n isHostRole,\n type CallMode,\n type MeetIdentity,\n type MeetingRecord,\n type MeetParticipant,\n type ParticipantIdentity,\n type ParticipantRole,\n type RoomName,\n type StageLayout,\n asUserId,\n type UserId,\n} from \"./types\";\n\nexport interface JoinRequest {\n readonly roomName: RoomName;\n readonly meetingId?: string | undefined;\n readonly slug?: string | undefined;\n /** `audio` joins with the camera off. Same room, same code path (D3). */\n readonly mode: CallMode;\n /**\n * Whether to ATTEMPT the microphone on join. Defaults to true. `false` is a\n * deliberate listen-only join — the pre-join screen's \"Join with microphone\"\n * toggle. Either way the join itself never depends on the outcome; a refused\n * device lands in `snapshot.media.microphone.unavailable`, not in a throw.\n */\n readonly microphone?: boolean | undefined;\n}\n\nexport interface RoomEngineOptions {\n store: MeetStore;\n tokens: TokenClient;\n identity: MeetIdentity;\n driverFactory: RoomDriverFactory;\n /** Canonical public metadata read; room packets alone never authorize teardown. */\n resolveMeeting?: ((slug: string) => Promise<MeetingRecord>) | undefined;\n onDiagnostic?: ((event: { level: \"info\" | \"warn\" | \"error\"; message: string; remedy?: string }) => void) | undefined;\n /** Fired when the local participant leaves for any reason, including kicked. */\n onLeft?: ((reason: string | null) => void) | undefined;\n now?: (() => number) | undefined;\n /** Remembered noise suppression / background choice (Meet wave 2). */\n effectsStorage?: EffectsStorage | undefined;\n /**\n * The device the person PICKED for each kind (the pre-join pickers, the\n * settings panel). Applied before any track is created — through 0.7.x the\n * pickers stored a choice nothing ever read, so every join used the browser\n * default whatever the screen said.\n */\n resolveDevice?: ((kind: \"audioinput\" | \"videoinput\" | \"audiooutput\") => string | null) | undefined;\n}\n\nexport interface RoomEngine {\n join(request: JoinRequest): Promise<void>;\n /**\n * 🚨 THE HOST SAID YES — COME IN.\n *\n * A lobby token is minted with `canPublish: false` and `canSubscribe: false`\n * (that is what makes the lobby real rather than a screen over a live\n * microphone), so admission is not a UI state change: the cached token has to\n * be thrown away and a NEW one minted with the grants the server now gives.\n * Without this the waiting room's own sentence — \"you will join automatically\n * once you are admitted\" — is a lie, and the guest waits forever.\n */\n rejoin(): Promise<void>;\n leave(): Promise<void>;\n setMicrophoneEnabled(enabled: boolean): Promise<void>;\n setCameraEnabled(enabled: boolean): Promise<void>;\n setScreenShareEnabled(enabled: boolean): Promise<void>;\n raiseHand(raised: boolean): Promise<void>;\n react(emoji: string): Promise<void>;\n /**\n * A PRIVATE message to one person (Meet wave 2). Data plane only, addressed\n * to that identity, NEVER saved — see `core/chat.ts` for the saved,\n * everyone-chat, which goes through the server.\n */\n sendPrivateChat(to: ParticipantIdentity, text: string): Promise<void>;\n /**\n * Change this participant's own media processing — noise suppression and the\n * camera background — on the live tracks, and remember it in this browser.\n * A refused effect is a diagnostic and a revert, never a lost camera.\n */\n setEffects(next: Partial<MediaEffects>): Promise<void>;\n /** Whether this browser can run a background effect at all (absent, never dead). */\n supportsVideoEffects(): boolean;\n /** Choose the speaker (audio output) for this meeting. */\n switchDevice(kind: \"audioinput\" | \"videoinput\" | \"audiooutput\", deviceId: string): Promise<void>;\n pin(identity: ParticipantIdentity | null): void;\n setLayout(layout: StageLayout): void;\n attach(\n identity: ParticipantIdentity,\n kind: \"camera\" | \"microphone\" | \"screen\",\n element: HTMLMediaElement,\n ): () => void;\n token(): RoomToken | null;\n dispose(): Promise<void>;\n}\n\n/** Where this browser keeps a participant's media choices. */\nexport interface EffectsStorage {\n load(): MediaEffects;\n save(effects: MediaEffects): void;\n}\n\n/** What the server puts in the token's participant metadata. */\ninterface ParticipantMetadata {\n readonly user_id?: string;\n readonly role?: string;\n readonly can_record?: boolean;\n readonly is_agent?: boolean;\n readonly avatar_url?: string;\n}\n\n/**\n * 🚨 THE SERVER'S WORD, ON TWO CARRIERS (MRI-A11, feedback `7418ef78`).\n *\n * aidream mints the role into the token's participant METADATA (a JSON blob)\n * AND as a LiveKit participant ATTRIBUTE. Both come out of one decision in\n * `services/meet/service.py`; neither can be written by a client. The attribute\n * is preferred because LiveKit delivers the attribute map on every roster\n * update, while a roster event can carry an empty metadata string — which is\n * precisely how, through 2026-09-08, EVERY participant projected as\n * \"participant\" and no host ever saw a host control in a browser.\n *\n * These strings are pinned on the server side too: `test_meet_service.py` reads\n * them out of THIS file and fails if the two sides drift.\n */\nexport const PARTICIPANT_ROLE_ATTRIBUTE = \"matrx.participant.role\";\nexport const PARTICIPANT_CAN_RECORD_ATTRIBUTE = \"matrx.participant.can_record\";\n\nconst KNOWN_ROLES: readonly ParticipantRole[] = [\"host\", \"cohost\", \"participant\", \"guest\"];\n\n/**\n * An unrecognized role is `participant` — never `host`. A word this package\n * does not know is a server that is ahead of it, and the safe reading of an\n * unknown claim is the one that grants nothing.\n */\nfunction parseRole(value: string | undefined): ParticipantRole {\n return KNOWN_ROLES.includes(value as ParticipantRole) ? (value as ParticipantRole) : \"participant\";\n}\n\n/**\n * Metadata is SERVER-MINTED and therefore trusted; it is still parsed\n * defensively, because a malformed blob must degrade a tile to \"participant\"\n * rather than throw inside a roster event and freeze the whole grid.\n */\nexport function projectParticipant(\n driver: DriverParticipant,\n joinedAt: string,\n): MeetParticipant {\n let metadata: ParticipantMetadata = {};\n if (driver.metadata !== null && driver.metadata.length > 0) {\n try {\n const parsed: unknown = JSON.parse(driver.metadata);\n if (typeof parsed === \"object\" && parsed !== null) {\n metadata = parsed as ParticipantMetadata;\n }\n } catch {\n metadata = {};\n }\n }\n const userId = typeof metadata.user_id === \"string\" ? asUserId(metadata.user_id) : null;\n return {\n identity: asParticipantIdentity(driver.identity),\n userId,\n // 🚨 A RAW LIVEKIT IDENTITY IS NEVER A NAME (MRI-A18). Through 0.4.12 this\n // line read `driver.name.length > 0 ? driver.name : driver.identity`, and\n // that single fallback put `guest:v-spk-1` on the participant strip, the\n // People panel, the meeting header and every Pin/Mute aria-label, in BOTH\n // lanes — inside the very structure `core/names.ts` is taught from. A\n // nameless tile is still a bug report nobody can action, so the fallback\n // stays; it is now the name book's HONEST placeholder (\"Unnamed guest\", or\n // the agent's product name) instead of the token. `store.setParticipants`\n // then upgrades this to the best name anything has ever learned.\n displayName: displayNameFor({}, driver.identity, driver.name),\n avatarUrl: typeof metadata.avatar_url === \"string\" ? metadata.avatar_url : null,\n // ATTRIBUTE FIRST, metadata second — see the constants above. Both are the\n // server's; the attribute is simply the one that always arrives.\n role: parseRole(driver.attributes[PARTICIPANT_ROLE_ATTRIBUTE] ?? metadata.role),\n canRecord:\n driver.attributes[PARTICIPANT_CAN_RECORD_ATTRIBUTE] === \"true\" ||\n metadata.can_record === true,\n isLocal: driver.isLocal,\n isAgent: metadata.is_agent === true,\n attributes: driver.attributes,\n micEnabled: driver.micEnabled,\n cameraEnabled: driver.cameraEnabled,\n screenSharing: driver.screenSharing,\n speaking: false,\n handRaised: false,\n quality: \"unknown\",\n joinedAt,\n };\n}\n\ninterface DataEnvelope {\n readonly id?: string;\n readonly at?: string;\n /** Epoch ms a hand went up — the queue's order. */\n readonly raisedAt?: number;\n /** A private chat message's addressee. */\n readonly to?: string;\n readonly raised?: boolean;\n readonly emoji?: string;\n readonly text?: string;\n readonly name?: string;\n}\n\nexport function createRoomEngine(options: RoomEngineOptions): RoomEngine {\n const { store, tokens, identity } = options;\n const now = options.now ?? (() => Date.now());\n let driver: MeetRoomDriver | null = null;\n let current: RoomToken | null = null;\n let joining: Promise<void> | null = null;\n // The request this engine last joined with, so an admitted guest can be let\n // in without the surface having to remember how it got here.\n let lastRequest: JoinRequest | null = null;\n let disposed = false;\n const confirmingEnds = new WeakSet<MeetRoomDriver>();\n\n async function leaveRoom(): Promise<void> {\n const target = driver;\n driver = null;\n if (current !== null) {\n tokens.invalidate(current.roomName);\n current = null;\n }\n store.setLocalTrack(\"microphone\", IDLE_TRACK);\n store.setLocalTrack(\"camera\", IDLE_TRACK);\n store.patch({ phase: \"left\" });\n await target?.disconnect();\n }\n\n async function confirmMeetingEnd(): Promise<void> {\n const meeting = store.snapshot().meeting;\n const target = driver;\n if (meeting === null || target === null || confirmingEnds.has(target) || options.resolveMeeting === undefined) return;\n confirmingEnds.add(target);\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const verified = await Promise.race([\n options.resolveMeeting(meeting.slug),\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(\"Meeting end verification timed out\")), 5000);\n }),\n ]);\n if (disposed || driver !== target || store.snapshot().meeting?.id !== meeting.id) return;\n if (verified.id !== meeting.id || verified.roomName !== meeting.roomName || verified.endedAt === null) {\n report(\"warn\", \"Meet ignored an unconfirmed meeting-end notice\", \"The canonical meeting is still live or does not match this room.\");\n return;\n }\n // Keep newer roster/metadata updates; only the durable ending is needed.\n const latest = store.snapshot().meeting;\n if (latest === null) return;\n store.patch({ meeting: { ...latest, endedAt: verified.endedAt } });\n await leaveRoom();\n } catch (error) {\n report(\"error\", `Meet could not confirm or finish meeting teardown: ${String(error)}`, \"Check the meeting link again; if media remains active, close this meeting tab.\");\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n confirmingEnds.delete(target);\n }\n }\n\n function report(level: \"info\" | \"warn\" | \"error\", message: string, remedy?: string): void {\n options.onDiagnostic?.(remedy === undefined ? { level, message } : { level, message, remedy });\n }\n\n function fail(error: unknown, operation: string): MeetError {\n const normalized = normalizeMeetError(error, operation);\n store.patch({\n phase: \"failed\",\n failure: { message: normalized.message, remedy: normalized.remedy },\n });\n report(\n normalized.code === \"session-unavailable\" ? \"warn\" : \"error\",\n normalized.message,\n normalized.remedy,\n );\n return normalized;\n }\n\n const handlers: RoomDriverHandlers = {\n participants(list) {\n const joinedAt = new Date(now()).toISOString();\n const before = new Set(store.snapshot().participants.map((p) => p.identity));\n store.setParticipants(list.map((entry) => projectParticipant(entry, joinedAt)));\n // 🚨 A HAND IS DATA-PLANE STATE, and the data plane has no history: a\n // person who joins after a hand went up would never see it, and the host\n // would call on people out of order. So each client RE-ANNOUNCES its own\n // raised hand, with its original time, when someone new arrives — the\n // queue position travels with it, and `store.setHand` keeps the first.\n const snapshot = store.snapshot();\n const newcomer = snapshot.participants.some(\n (participant) => !participant.isLocal && !before.has(participant.identity),\n );\n const me = snapshot.participants.find((p) => p.identity === snapshot.localIdentity);\n if (newcomer && before.size > 0 && me?.handRaised === true) {\n void publish(DATA_TOPICS.hand, { raised: true, raisedAt: me.handRaisedAt ?? now() }).catch(\n () => undefined,\n );\n }\n },\n roomMetadata(metadata) {\n // THE SERVER'S ROOM STATE (Meet wave 2). Only `UpdateRoomMetadata` writes\n // it, and only `services/meet/moderation.py` calls that. A malformed or\n // empty string means \"nothing set\", never a throw inside a room event.\n let spotlight: ParticipantIdentity | null = null;\n if (metadata.length > 0) {\n try {\n const parsed: unknown = JSON.parse(metadata);\n if (typeof parsed === \"object\" && parsed !== null) {\n const value = (parsed as { spotlight?: unknown }).spotlight;\n if (typeof value === \"string\" && value.length > 0) spotlight = asParticipantIdentity(value);\n }\n } catch {\n report(\n \"warn\",\n \"meet: the room's metadata is not JSON, so no spotlight was read from it\",\n \"Only aidream writes room metadata; check services/meet/moderation.py.\",\n );\n }\n }\n if (store.snapshot().spotlight !== spotlight) store.patch({ spotlight });\n },\n activeSpeakers(identities) {\n store.setSpeaking(identities.map(asParticipantIdentity));\n },\n quality(who, value) {\n store.setQuality(asParticipantIdentity(who), value);\n },\n connectionState(state) {\n // `reconnecting` is a VISIBLE state, not a silent one: a frozen tile with\n // no explanation is indistinguishable from a crashed app.\n if (state === \"connected\") store.patch({ phase: \"connected\", failure: null });\n else if (state === \"reconnecting\") store.patch({ phase: \"reconnecting\" });\n else if (state === \"connecting\") store.patch({ phase: \"connecting\" });\n },\n transcription(event) {\n // A CAPTION IS A HINT (D16). It is stored as one, next to the durable\n // rows, and the reconciliation in `transcript.ts` decides which of the two\n // a line ends up being. Nothing else in this package reads captions.\n const snapshot = store.snapshot();\n const meeting = snapshot.meeting;\n if (meeting === null) {\n // A caption with no meeting record has nothing durable to reconcile\n // against later. An ad-hoc call room is exactly that case; dropping it\n // is correct, and it is not silent — it is stated here.\n return;\n }\n // `lk.transcribed_participant_identity` is supplied by the publisher and\n // only says who they CLAIM to be transcribing. The stream's publisher is\n // the SFU-reported identity; captions are admitted only from this\n // meeting's deterministic note-taker. This remains display-only (D16),\n // but a room participant cannot write a fake line into the caption rail.\n // This check deliberately does not wait for a roster event: the first\n // note-taker utterance may arrive before its roster projection.\n if (event.publisherIdentity !== noteTakerIdentity(meeting.id)) {\n report(\n \"warn\",\n \"meet: ignored a caption from a participant that is not this meeting's note-taker\",\n \"Captions are accepted only from the server-dispatched note-taker; the durable transcript remains authoritative.\",\n );\n return;\n }\n const speakerIdentity = asParticipantIdentity(event.speakerIdentity);\n const speaker = snapshot.participants.find(\n (participant) => participant.identity === speakerIdentity,\n );\n store.ingestCaption(\n captionSegment({\n captionId: event.segmentId,\n meetingId: meeting.id,\n identity: speakerIdentity,\n // 🚨 ONE ANSWER TO \"WHO SAID THAT\" (MRI-A16). This line used to fall\n // back to `event.speakerIdentity` — the raw LiveKit token — which is\n // how a guest's caption rail read `guest:c8-spk-1` in the same second\n // the host's read \"Ada Lovelace\". The book keeps the last known name\n // for somebody who has left, and says \"Unnamed guest\" when nothing\n // anywhere has ever known one. It never prints a token.\n speaker: displayNameFor(snapshot.names, speakerIdentity, speaker?.displayName),\n text: event.text,\n final: event.final,\n startedAt: event.at,\n }),\n );\n },\n data(topic, payload, from) {\n // 🚨 THE SERVER'S OWN EVENTS COME FIRST, and they are the only live feed a\n // session-less guest has (MRI-A12). They are handled before the `mx.*`\n // control plane because they are a different KIND of message: published by\n // the platform with a `roomAdmin` grant no participant token can claim,\n // carrying durable rows rather than a sender's intent.\n if (isRoomEventTopic(topic)) {\n // `matrx.meet.*` is a server namespace, not an ACL. Any participant\n // may publish to a topic, including one with an agent-looking name;\n // only RoomService.SendData reaches the SDK without a participant.\n if (from !== null) {\n report(\n \"warn\",\n `meet: ignored participant-published server event on ${topic}`,\n \"Only aidream may publish matrx.meet.* events. The durable meeting record remains unchanged.\",\n );\n return;\n }\n let body: unknown;\n try {\n body = JSON.parse(payload);\n } catch {\n report(\n \"warn\",\n `meet: dropped an unparseable room event on ${topic}`,\n \"This topic is published by aidream only. Non-JSON here means a client is \" +\n \"publishing under the server's namespace, or the payload was truncated.\",\n );\n return;\n }\n if (topic === ROOM_EVENTS.ended && options.resolveMeeting !== undefined) {\n const meeting = store.snapshot().meeting;\n if (typeof body === \"object\" && body !== null && \"meeting_id\" in body && body.meeting_id === meeting?.id) {\n void confirmMeetingEnd();\n } else {\n report(\"warn\", \"Meet ignored an ending for another or missing meeting\", \"Only a matching canonical meeting can end this transport.\");\n }\n return;\n }\n const outcome = applyRoomEvent({ store, topic, payload: body, now });\n if (!outcome.handled) {\n // NEVER SILENT. A dropped room event is a note, a decision or an\n // ending that a guest will simply never see, and the reason has to be\n // reachable from the surface rather than from a debugger.\n report(\n \"warn\",\n `meet: ignored a room event on ${topic} — ${outcome.ignored ?? \"no reason given\"}`,\n \"The durable row still exists behind the meeting link. Signed-in members \" +\n \"receive it over Postgres Changes; a guest sees it on their next join.\",\n );\n }\n return;\n }\n let envelope: DataEnvelope = {};\n try {\n const parsed: unknown = JSON.parse(payload);\n if (typeof parsed === \"object\" && parsed !== null) envelope = parsed as DataEnvelope;\n } catch {\n report(\n \"warn\",\n `meet: dropped an unparseable data message on ${topic}`,\n \"A sender is publishing non-JSON on a reserved mx.* topic. Use publishData through \" +\n \"the engine so the envelope is always well formed.\",\n );\n return;\n }\n const sender = asParticipantIdentity(from ?? \"\");\n switch (topic) {\n case DATA_TOPICS.hand:\n store.setHand(\n sender,\n envelope.raised === true,\n typeof envelope.raisedAt === \"number\" ? envelope.raisedAt : now(),\n );\n return;\n case DATA_TOPICS.reaction:\n if (typeof envelope.emoji === \"string\") {\n store.addReaction({\n id: envelope.id ?? `${sender}-${now()}`,\n identity: sender,\n emoji: envelope.emoji,\n at: now(),\n });\n }\n return;\n case DATA_TOPICS.chat:\n // ONLY PRIVATE MESSAGES ride the data plane since 0.8: a message to\n // everyone is SAVED through the server and arrives as the server's\n // `matrx.meet.chat`. A participant's un-addressed `mx.chat` packet is\n // an older client's ephemeral chat — shown, never mistaken for saved.\n if (typeof envelope.text === \"string\") {\n const local = store.snapshot().localIdentity;\n store.addChat({\n id: envelope.id ?? `${sender}-${now()}`,\n identity: sender,\n displayName: envelope.name ?? sender,\n text: envelope.text,\n at: envelope.at ?? new Date(now()).toISOString(),\n ...(typeof envelope.to === \"string\" && local !== null ? { to: local } : {}),\n });\n }\n return;\n default:\n // Unknown topics are IGNORED, never thrown on — that is what lets a\n // newer client ship a new in-room feature without breaking old ones.\n return;\n }\n },\n disconnected(reason) {\n // THE SERVER ENDED THIS SESSION (removed, room closed, token revoked), so the\n // cached token is dead: the next Join must mint again and read the server's\n // own decision (\"A host removed you…\"). Reusing it showed \"invalid token:\n // revoked\" under a camera-refusal remedy (production 2026-09-27).\n if (current !== null) {\n tokens.invalidate(current.roomName);\n current = null;\n }\n store.patch({ phase: \"left\" });\n options.onLeft?.(reason);\n },\n };\n\n async function connect(request: JoinRequest): Promise<void> {\n store.patch({ phase: \"requesting-token\", failure: null });\n const token = await tokens.get({\n roomName: request.roomName,\n identity,\n ...(request.meetingId !== undefined ? { meetingId: request.meetingId } : {}),\n ...(request.slug !== undefined ? { slug: request.slug } : {}),\n });\n current = token;\n // 🚨 THE GRANTS LAND WITH THE TOKEN, before any roster exists (MRI-A11).\n // Waiting for the LiveKit roster to learn that this person is the host means\n // the host's own controls flicker in — or, when a roster event arrives with\n // empty metadata, never appear at all. That was the shipped defect.\n store.patch({\n localIdentity: token.identity,\n grants: {\n role: token.role,\n canRecord: token.canRecord,\n canPublish: token.canPublish,\n canSubscribe: token.canSubscribe,\n },\n });\n\n // THE LOBBY IS A PHASE, NOT AN ERROR (D6). The server said \"wait\"; the UI\n // shows the waiting room and the room channel delivers the host's decision.\n if (token.lobby) {\n store.patch({ phase: \"lobby\" });\n return;\n }\n\n store.patch({ phase: \"connecting\" });\n const created = await options.driverFactory(handlers);\n if (disposed) {\n // Unmounted mid-connect. Disconnect the room we just built rather than\n // leaking it — this is the \"camera light stays on\" bug.\n await created.disconnect();\n return;\n }\n driver = created;\n await created.connect(token.serverUrl, token.token);\n\n // 🚨 IN THE ROOM. Attendance is settled HERE, before a single device is\n // touched. Everything below is best-effort publishing; nothing below can\n // unwind the join. See `attendance.ts` for the defect this closes.\n store.patch({ phase: \"connected\", failure: null });\n store.setLocalTrack(\"microphone\", IDLE_TRACK);\n store.setLocalTrack(\"camera\", IDLE_TRACK);\n\n // THE REMEMBERED CHOICES GO ON BEFORE ANY DEVICE DOES, so the first frame\n // anyone sees is already blurred and the first word already cleaned.\n const effects = options.effectsStorage?.load() ?? store.snapshot().effects;\n store.patch({ effects });\n // Only what DIFFERS from the browser default is applied on the way in: a\n // default join touches nothing it does not have to.\n if (!effects.noiseSuppression || effects.background !== \"none\") {\n try {\n await applyEffects(created, effects);\n } catch {\n // Reported inside; the join never depends on an effect.\n }\n }\n for (const kind of [\"audioinput\", \"videoinput\", \"audiooutput\"] as const) {\n const chosen = options.resolveDevice?.(kind) ?? null;\n if (chosen === null || chosen === \"default\") continue;\n try {\n await created.switchDevice(kind, chosen);\n } catch (error) {\n const normalized = normalizeDeviceError(error, `meet.switchDevice(${kind})`);\n report(\"warn\", normalized.message, normalized.remedy);\n }\n }\n\n if (request.mode === \"video\") {\n await enableTrack(created, \"camera\", true);\n }\n if (request.microphone !== false) {\n await enableTrack(created, \"microphone\", true);\n }\n }\n\n /**\n * THE ONE PATH that turns a local device on or off — used by the join and by\n * the in-room controls alike, so \"enable it later\" cannot behave differently\n * from \"enable it on the way in\". A refusal is recorded as state with the\n * browser's own reason and a remedy, reported as a diagnostic, and returned;\n * it is never thrown, because there is no caller for whom losing the room is\n * the right answer to a busy microphone.\n */\n async function enableTrack(\n target: MeetRoomDriver,\n kind: \"microphone\" | \"camera\",\n enabled: boolean,\n ): Promise<LocalTrackState> {\n try {\n if (kind === \"microphone\") await target.setMicrophoneEnabled(enabled);\n else await target.setCameraEnabled(enabled);\n const state: LocalTrackState = { enabled, unavailable: null };\n store.setLocalTrack(kind, state);\n return state;\n } catch (error) {\n const normalized = normalizeDeviceError(error, `meet.${kind}`);\n const state: LocalTrackState = { enabled: false, unavailable: unavailableFrom(normalized) };\n store.setLocalTrack(kind, state);\n report(\"warn\", normalized.message, normalized.remedy);\n return state;\n }\n }\n\n async function publish(\n topic: string,\n body: Record<string, unknown>,\n to?: readonly string[],\n ): Promise<void> {\n if (driver === null) return;\n await driver.publishData(topic, JSON.stringify(body), to);\n }\n\n async function applyEffects(target: MeetRoomDriver, effects: MediaEffects): Promise<void> {\n try {\n await target.setAudioProcessing?.({\n noiseSuppression: effects.noiseSuppression,\n echoCancellation: true,\n autoGainControl: true,\n });\n } catch (error) {\n report(\"warn\", `meet: noise suppression could not be applied: ${String(error)}`, \"The microphone keeps working without it.\");\n }\n if (target.setVideoEffect === undefined) return;\n const effect: VideoEffect =\n effects.background === \"blur\"\n ? { kind: \"blur\" }\n : effects.background === \"image\" && effects.backgroundImage !== null\n ? { kind: \"image\", imageUrl: effects.backgroundImage }\n : { kind: \"none\" };\n if (effect.kind !== \"none\" && target.supportsVideoEffects?.() === false) return;\n try {\n await target.setVideoEffect(effect);\n } catch (error) {\n const normalized = normalizeMeetError(error, \"meet.setVideoEffect\");\n report(\"warn\", normalized.message, normalized.remedy);\n throw normalized;\n }\n }\n\n return {\n join(request) {\n // SINGLE FLIGHT: a strict-mode double effect and a user's second click\n // share one join. Two joins for one identity make LiveKit drop the first.\n if (joining !== null) return joining;\n lastRequest = request;\n joining = connect(request)\n .catch((error: unknown) => {\n throw fail(error, \"meet.join\");\n })\n .finally(() => {\n joining = null;\n });\n return joining;\n },\n async rejoin() {\n const request = lastRequest;\n if (request === null) {\n // Nothing to rejoin is not an error and never a silent no-op: it means\n // this engine never joined, which a caller can only reach by wiring the\n // admission signal to a room nobody is waiting in.\n report(\n \"warn\",\n \"meet.rejoin: this room engine has never joined, so there is nothing to rejoin\",\n \"Call join() first. An admission verdict for a participant who never knocked is \" +\n \"ignored rather than minting a token nobody asked for.\",\n );\n return;\n }\n if (joining !== null) return joining;\n // THE LOBBY TOKEN IS THROWN AWAY. It grants neither publish nor\n // subscribe; reusing it would put the admitted guest in the room as a\n // participant who can neither speak nor hear.\n tokens.invalidate(request.roomName);\n current = null;\n joining = connect(request)\n .catch((error: unknown) => {\n throw fail(error, \"meet.rejoin\");\n })\n .finally(() => {\n joining = null;\n });\n return joining;\n },\n leave: leaveRoom,\n // Turning a device on mid-meeting is the SAME operation as turning it on\n // during the join, so it runs the same function. A failure here used to\n // stamp the room `failed` — a busy microphone would blank a live meeting.\n async setMicrophoneEnabled(enabled) {\n if (driver === null) return;\n await enableTrack(driver, \"microphone\", enabled);\n },\n async setCameraEnabled(enabled) {\n if (driver === null) return;\n await enableTrack(driver, \"camera\", enabled);\n },\n async setScreenShareEnabled(enabled) {\n if (driver === null) return;\n try {\n await driver.setScreenShareEnabled(enabled);\n } catch (error) {\n throw fail(error, \"meet.setScreenShareEnabled\");\n }\n },\n async raiseHand(raised) {\n const local = store.snapshot().localIdentity;\n // Applied LOCALLY FIRST. A hand that only rises when the round trip\n // returns feels broken, and the data plane is reliable-ordered anyway.\n if (local !== null) store.setHand(local, raised);\n await publish(DATA_TOPICS.hand, { raised, raisedAt: now() });\n },\n async react(emoji) {\n const local = store.snapshot().localIdentity;\n const id = `${local ?? \"local\"}-${now()}`;\n if (local !== null) {\n store.addReaction({ id, identity: local, emoji, at: now() });\n }\n await publish(DATA_TOPICS.reaction, { id, emoji });\n },\n async sendPrivateChat(to, text) {\n const trimmed = text.trim();\n if (trimmed.length === 0) return;\n const local = store.snapshot().localIdentity;\n const id = `${local ?? \"local\"}-${now()}`;\n const at = new Date(now()).toISOString();\n if (local !== null) {\n store.addChat({ id, identity: local, displayName: identity.displayName, text: trimmed, at, to });\n }\n await publish(\n DATA_TOPICS.chat,\n { id, text: trimmed, at, name: identity.displayName, to },\n [to],\n );\n },\n async setEffects(next) {\n const previous = store.snapshot().effects;\n const merged: MediaEffects = { ...previous, ...next };\n store.patch({ effects: merged });\n options.effectsStorage?.save(merged);\n if (driver === null) return;\n try {\n await applyEffects(driver, merged);\n } catch {\n // The camera keeps running without the effect; the choice reverts so\n // the control never claims an effect that is not on screen.\n const reverted: MediaEffects = { ...merged, background: previous.background, backgroundImage: previous.backgroundImage };\n store.patch({ effects: reverted });\n options.effectsStorage?.save(reverted);\n }\n },\n supportsVideoEffects() {\n return driver?.supportsVideoEffects?.() ?? false;\n },\n async switchDevice(kind, deviceId) {\n if (driver === null) return;\n await driver.switchDevice(kind, deviceId);\n },\n pin(who) {\n store.patch({ pinned: who, layout: who === null ? \"grid\" : \"speaker\" });\n },\n setLayout(layout) {\n store.patch({ layout });\n },\n attach(who, kind, element) {\n if (driver === null) return () => undefined;\n return driver.attach(who, kind, element);\n },\n token: () => current,\n async dispose() {\n disposed = true;\n if (driver !== null) {\n const target = driver;\n driver = null;\n await target.disconnect();\n }\n store.reset();\n },\n };\n}\n\n/** Exported for the host-power check in UI code — one definition, one rank. */\nexport function canModerate(participant: MeetParticipant | undefined): boolean {\n return participant !== undefined && isHostRole(participant.role);\n}\n\nexport function hostUserIds(participants: readonly MeetParticipant[]): readonly UserId[] {\n return participants\n .filter((participant) => participant.role === \"host\" && participant.userId !== null)\n .map((participant) => participant.userId as UserId);\n}\n","/**\n * A PARTICIPANT'S OWN MEDIA CHOICES, REMEMBERED (Meet wave 2).\n *\n * Noise suppression and the camera background are personal and per device —\n * Zoom and Meet both remember them — so they live in this browser, never on a\n * server. Blocked storage means the defaults (suppression on, no background),\n * never a failed join.\n */\n\nimport type { EffectsStorage } from \"./room\";\nimport { DEFAULT_EFFECTS, type MediaEffects } from \"./store\";\n\nfunction coerce(value: unknown): MediaEffects {\n if (typeof value !== \"object\" || value === null) return DEFAULT_EFFECTS;\n const row = value as Record<string, unknown>;\n const background =\n row[\"background\"] === \"blur\" || row[\"background\"] === \"image\" ? row[\"background\"] : \"none\";\n const backgroundImage = typeof row[\"backgroundImage\"] === \"string\" ? row[\"backgroundImage\"] : null;\n return {\n noiseSuppression: row[\"noiseSuppression\"] !== false,\n background: background === \"image\" && backgroundImage === null ? \"none\" : background,\n backgroundImage,\n };\n}\n\nexport function createWebEffectsStorage(key = \"mx.meet.effects\"): EffectsStorage {\n let memory: MediaEffects = DEFAULT_EFFECTS;\n const storage = (globalThis as { localStorage?: Storage }).localStorage;\n return {\n load() {\n if (storage === undefined) return memory;\n try {\n const raw = storage.getItem(key);\n return raw === null ? memory : coerce(JSON.parse(raw));\n } catch {\n return memory;\n }\n },\n save(effects) {\n memory = effects;\n try {\n storage?.setItem(key, JSON.stringify(effects));\n } catch {\n // Storage blocked: the choice lasts for this visit.\n }\n },\n };\n}\n","/**\n * THE IN-ROOM SERVER CALLS (Meet wave 2) — host moderation and the SAVED chat.\n *\n * 🚨 **Why these are server calls and not data packets.** Through 0.7.x a host's\n * \"Mute\" and \"Remove\" were published on the room's data plane (`mx.host`) and\n * nothing anywhere listened: the buttons did nothing. A client cannot be the\n * authority on host power, and a guest cannot write the database. So both go to\n * aidream (`POST /v1/meet/moderate`, `POST|GET /v1/meet/chat`), which decides the\n * actor's role from the meeting itself, performs the act through LiveKit's server\n * API, writes what is durable, and tells the room on its own `matrx.meet.*` topic.\n *\n * A guest proves who they are with the room pass this server signed for them, in\n * `x-meet-room-token` — a header, never a URL.\n */\n\nimport { refusalFromResponse } from \"./ai\";\nimport type { MeetApi } from \"./api\";\nimport { MeetError } from \"./errors\";\nimport { chatFromRow } from \"./room-events\";\nimport type { MeetStore, RoomChatMessage } from \"./store\";\nimport { MEET_ROUTES, ROOM_TOKEN_HEADER } from \"./tokens\";\nimport type { ParticipantIdentity } from \"./types\";\n\n/** Every host power the server performs. One vocabulary with `services/meet/moderation.py`. */\nexport type ModerationAction =\n | \"mute\"\n | \"stop_video\"\n | \"stop_screen\"\n | \"mute_all\"\n | \"ask_unmute\"\n | \"ask_all_unmute\"\n | \"spotlight\"\n | \"lower_hand\"\n | \"lower_all_hands\"\n | \"make_cohost\"\n | \"revoke_cohost\"\n | \"transfer_host\"\n | \"rename\"\n | \"remove\"\n | \"report\";\n\nexport const MODERATION_ACTIONS: readonly ModerationAction[] = [\n \"mute\",\n \"stop_video\",\n \"stop_screen\",\n \"mute_all\",\n \"ask_unmute\",\n \"ask_all_unmute\",\n \"spotlight\",\n \"lower_hand\",\n \"lower_all_hands\",\n \"make_cohost\",\n \"revoke_cohost\",\n \"transfer_host\",\n \"rename\",\n \"remove\",\n \"report\",\n];\n\nexport interface ModerationRequest {\n readonly action: ModerationAction;\n readonly identity?: ParticipantIdentity | null | undefined;\n readonly name?: string | undefined;\n readonly reason?: string | undefined;\n}\n\nexport interface ModerationResult {\n readonly action: ModerationAction;\n readonly affected: readonly string[];\n /** The server's sentence for the actor. */\n readonly message: string;\n}\n\nexport interface InRoomClient {\n moderate(request: ModerationRequest): Promise<ModerationResult>;\n /** Send a message to EVERYONE. Saved; shows at once as pending, then as saved. */\n sendChat(text: string): Promise<void>;\n /** Read the saved chat once per join, so a late joiner sees what was said. */\n loadChat(): Promise<void>;\n}\n\nexport interface InRoomClientOptions {\n api: MeetApi;\n store: MeetStore;\n /** The room pass for THIS meeting, or null (a signed-in member needs none). */\n resolveRoomToken: () => string | null;\n now?: (() => number) | undefined;\n}\n\nexport function createInRoomClient(options: InRoomClientOptions): InRoomClient {\n const { api, store } = options;\n const now = options.now ?? (() => Date.now());\n\n function meetingId(operation: string): string {\n const meeting = store.snapshot().meeting;\n if (meeting === null) {\n throw new MeetError(\n \"not-found\",\n `${operation}: this room has no meeting record`,\n \"Moderation and saved chat belong to a meeting. An ad-hoc call has neither.\",\n );\n }\n return meeting.id;\n }\n\n function headers(): Record<string, string> | undefined {\n const token = options.resolveRoomToken();\n return token === null ? undefined : { [ROOM_TOKEN_HEADER]: token };\n }\n\n function refusal(response: Response, operation: string, remedy: string): Promise<MeetError> {\n return refusalFromResponse(response, operation, remedy);\n }\n\n return {\n async moderate(request) {\n const operation = `meet.moderate(${request.action})`;\n const hdrs = headers();\n const response = await api.request({\n path: MEET_ROUTES.moderate,\n method: \"POST\",\n operation,\n body: {\n meeting_id: meetingId(operation),\n action: request.action,\n ...(request.identity != null ? { identity: request.identity } : {}),\n ...(request.name !== undefined ? { name: request.name } : {}),\n ...(request.reason !== undefined ? { reason: request.reason } : {}),\n },\n ...(hdrs !== undefined ? { headers: hdrs } : {}),\n });\n if (!response.ok) {\n throw await refusal(\n response,\n operation,\n \"Nothing was changed. The server decides host powers from the meeting itself.\",\n );\n }\n const payload = (await response.json()) as Record<string, unknown>;\n return {\n action: request.action,\n affected: Array.isArray(payload[\"affected\"])\n ? payload[\"affected\"].filter((value): value is string => typeof value === \"string\")\n : [],\n message: typeof payload[\"message\"] === \"string\" ? payload[\"message\"] : \"Done.\",\n };\n },\n\n async sendChat(text) {\n const body = text.trim();\n if (body.length === 0) return;\n const operation = \"meet.sendChat\";\n const id = meetingId(operation);\n const snapshot = store.snapshot();\n const me = snapshot.participants.find((p) => p.identity === snapshot.localIdentity);\n // PENDING AT ONCE: a message that appears only after a round trip feels\n // broken. It is marked pending (not `saved`) until the server's row lands.\n const localId = `pending-${now()}`;\n const pending: RoomChatMessage = {\n id: localId,\n identity: snapshot.localIdentity ?? (\"local\" as ParticipantIdentity),\n displayName: me?.displayName ?? \"You\",\n text: body,\n at: new Date(now()).toISOString(),\n saved: false,\n };\n store.addChat(pending);\n const hdrs = headers();\n let response: Response;\n try {\n response = await api.request({\n path: MEET_ROUTES.chat,\n method: \"POST\",\n operation,\n body: { meeting_id: id, body },\n ...(hdrs !== undefined ? { headers: hdrs } : {}),\n });\n } catch (error) {\n store.settleChat(localId, { failed: \"Not sent — the server could not be reached.\" });\n throw error;\n }\n if (!response.ok) {\n const error = await refusal(response, operation, \"Your message was not sent.\");\n store.settleChat(localId, { failed: error.message });\n throw error;\n }\n const saved = chatFromRow((await response.json()) as Record<string, unknown>);\n if (saved === null) {\n store.settleChat(localId, { failed: \"The server's answer could not be read.\" });\n return;\n }\n store.settleChat(localId, saved);\n },\n\n async loadChat() {\n const operation = \"meet.loadChat\";\n const id = meetingId(operation);\n const hdrs = headers();\n const response = await api.request({\n path: `${MEET_ROUTES.chat}?meeting_id=${encodeURIComponent(id)}`,\n method: \"GET\",\n operation,\n ...(hdrs !== undefined ? { headers: hdrs } : {}),\n });\n if (!response.ok) {\n throw await refusal(\n response,\n operation,\n \"Messages sent before you joined could not be read. New messages still arrive.\",\n );\n }\n const payload = (await response.json()) as { messages?: unknown };\n const rows = Array.isArray(payload.messages) ? payload.messages : [];\n const messages = rows\n .map((row) =>\n typeof row === \"object\" && row !== null ? chatFromRow(row as Record<string, unknown>) : null,\n )\n .filter((message): message is RoomChatMessage => message !== null);\n store.loadChat(messages);\n },\n };\n}\n","/**\n * THE ONE PLACE `livekit-client` IS TOUCHED.\n *\n * Everything above this file talks to `MeetRoomDriver`. That containment is\n * what lets the engine's whole behavior — ring timeouts, admission, escalation,\n * reconnection — be proven in a node test, and it is why an SDK upgrade is a\n * single-file review rather than a package-wide audit.\n *\n * 🚨 **THE IMPORT IS DYNAMIC, DELIBERATELY.** `import type` is erased, and the\n * runtime `await import(\"livekit-client\")` happens inside `connect()`. So:\n * importing `@ai-matrx/meet` during SSR, or on a page that renders a call\n * BUTTON but never a call, pulls in none of the media SDK and touches no\n * browser API (independence contract §4). A static import here would put ~400KB\n * of WebRTC into every consumer's first load and break RSC rendering.\n *\n * The mapping helpers below are exported for their own tests: an SDK enum\n * renamed upstream must fail a named test, not silently become \"unknown\" on\n * every tile.\n */\n\nimport type {\n ConnectionQuality as LiveKitQuality,\n Participant,\n Room,\n RoomOptions,\n} from \"livekit-client\";\nimport { MeetError, normalizeDeviceError } from \"./errors\";\nimport {\n TRANSCRIPTION_ATTRIBUTES,\n TRANSCRIPTION_TOPIC,\n type AudioProcessing,\n type DriverConnectionState,\n type DriverParticipant,\n type DriverTrackKind,\n type MeetRoomDriver,\n type RoomDriverHandlers,\n type VideoEffect,\n} from \"./room-driver\";\nimport type { ConnectionQuality } from \"./types\";\n\n/**\n * LiveKit's quality enum → ours. Mapped explicitly rather than cast: the SDK\n * has five states and our UI has five sentences, and an unmapped one must\n * degrade to `unknown` (an honest \"we don't know\") rather than to `excellent`\n * (a lie that hides a failing call).\n */\nexport function mapQuality(quality: LiveKitQuality | string): ConnectionQuality {\n switch (quality) {\n case \"excellent\":\n return \"excellent\";\n case \"good\":\n return \"good\";\n case \"poor\":\n return \"poor\";\n case \"lost\":\n return \"lost\";\n default:\n return \"unknown\";\n }\n}\n\nexport function mapConnectionState(state: string): DriverConnectionState {\n switch (state) {\n case \"connected\":\n return \"connected\";\n case \"connecting\":\n return \"connecting\";\n case \"reconnecting\":\n case \"signalReconnecting\":\n return \"reconnecting\";\n default:\n return \"disconnected\";\n }\n}\n\n/**\n * A LiveKit participant → our snapshot.\n *\n * 🚨 `name` IS REPORTED EXACTLY AS LIVEKIT GAVE IT, empty string and all\n * (MRI-A18). Through 0.4.12 it fell back to the identity here, which meant a\n * driver — the thing furthest from any screen — invented a \"name\" that\n * `core/names.ts` then had to recognize and refuse. A driver reports; it does\n * not name. The one fallback lives in `projectParticipant`, and it is the name\n * book's honest placeholder rather than a token.\n */\nexport function snapshotParticipant(\n participant: Pick<\n Participant,\n \"identity\" | \"name\" | \"metadata\" | \"isMicrophoneEnabled\" | \"isCameraEnabled\" | \"isScreenShareEnabled\"\n > & { attributes?: Readonly<Record<string, string>> | undefined },\n isLocal: boolean,\n): DriverParticipant {\n const name = participant.name;\n return {\n identity: participant.identity,\n name: name ?? \"\",\n metadata: participant.metadata ?? null,\n // ATTRIBUTES ARE PART OF THE SNAPSHOT, not read ad hoc later: the note-taker\n // announces the consent notice here (D10) and the roster is the only place\n // this package looks at a participant.\n attributes: participant.attributes ?? {},\n isLocal,\n micEnabled: participant.isMicrophoneEnabled,\n cameraEnabled: participant.isCameraEnabled,\n screenSharing: participant.isScreenShareEnabled,\n };\n}\n\nexport interface LiveKitDriverOptions {\n /** Adaptive stream + dynacast default ON — R5 scale honesty, not a knob. */\n roomOptions?: RoomOptions | undefined;\n}\n\n/** The browser defaults every call product ships with. */\nexport const DEFAULT_AUDIO_PROCESSING: AudioProcessing = {\n noiseSuppression: true,\n echoCancellation: true,\n autoGainControl: true,\n};\n\n/**\n * Background effects run a segmentation model on the GPU (MediaPipe via\n * `@livekit/track-processors`). A browser without `OffscreenCanvas` or WebGL2\n * cannot — the control is then ABSENT, never a toggle that silently fails.\n */\nexport function videoEffectsSupported(): boolean {\n const scope = globalThis as unknown as {\n OffscreenCanvas?: unknown;\n document?: { createElement(tag: string): { getContext(kind: string): unknown } };\n };\n if (typeof scope.OffscreenCanvas === \"undefined\" || scope.document === undefined) return false;\n try {\n return scope.document.createElement(\"canvas\").getContext(\"webgl2\") !== null;\n } catch {\n return false;\n }\n}\n\n/**\n * Put the chosen effect on the local camera. The processor package is imported\n * lazily, exactly like `livekit-client` itself, so a meeting nobody blurs never\n * downloads a segmentation model.\n */\nasync function applyVideoEffect(target: Room, effect: VideoEffect): Promise<void> {\n const { Track } = await import(\"livekit-client\");\n const track = target.localParticipant.getTrackPublication(Track.Source.Camera)?.track as\n | {\n setProcessor(processor: unknown): Promise<void>;\n stopProcessor(): Promise<void>;\n }\n | undefined;\n if (track === undefined) return; // camera off: applied when it turns on.\n try {\n if (effect.kind === \"none\") {\n await track.stopProcessor();\n return;\n }\n const processors = await import(\"@livekit/track-processors\");\n const processor =\n effect.kind === \"blur\"\n ? processors.BackgroundBlur(effect.radius ?? 12)\n : processors.VirtualBackground(effect.imageUrl);\n await track.setProcessor(processor);\n } catch (error) {\n throw new MeetError(\n \"media-unsupported\",\n \"The background effect could not start on this camera\",\n \"Background effects need a browser with WebGL2 (current Chrome, Edge, Firefox or Safari). \" +\n \"Your video continues without the effect.\",\n error,\n );\n }\n}\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\nexport function createLiveKitDriver(\n handlers: RoomDriverHandlers,\n options: LiveKitDriverOptions = {},\n): MeetRoomDriver {\n let room: Room | null = null;\n /**\n * The roster projection for the CURRENT room, kept out here so `connect()`\n * can fire it once the transport is up. See the call site for why.\n */\n let projectRoster: (() => void) | null = null;\n /** What the person chose, kept so a re-enabled track gets it too. */\n let audioCapture: AudioProcessing = DEFAULT_AUDIO_PROCESSING;\n let videoEffect: VideoEffect = { kind: \"none\" };\n\n async function load(): Promise<Room> {\n if (room !== null) return room;\n let module: typeof import(\"livekit-client\");\n try {\n module = await import(\"livekit-client\");\n } catch (error) {\n throw new MeetError(\n \"misconfigured\",\n \"livekit-client could not be loaded\",\n \"`livekit-client` is a dependency of @ai-matrx/meet and is imported lazily at \" +\n \"connect time. If this failed, the bundler excluded it — remove it from any \" +\n \"`external`/`serverExternalPackages` list, or pass your own driver factory.\",\n error,\n );\n }\n const { Room: LiveKitRoom, RoomEvent, Track } = module;\n const created = new LiveKitRoom({\n // R5: large meetings degrade gracefully instead of melting a laptop.\n adaptiveStream: true,\n dynacast: true,\n ...options.roomOptions,\n });\n\n const roster = (): void => {\n const local = snapshotParticipant(created.localParticipant, true);\n const remotes = [...created.remoteParticipants.values()].map((participant) =>\n snapshotParticipant(participant, false),\n );\n // The FULL roster every time. Every one of these six events changes what\n // a tile must render, and a delta protocol across six sources drifts.\n handlers.participants([local, ...remotes]);\n };\n\n projectRoster = roster;\n\n created\n .on(RoomEvent.ParticipantConnected, roster)\n .on(RoomEvent.ParticipantDisconnected, roster)\n .on(RoomEvent.TrackSubscribed, roster)\n .on(RoomEvent.TrackUnsubscribed, roster)\n .on(RoomEvent.TrackMuted, roster)\n .on(RoomEvent.TrackUnmuted, roster)\n .on(RoomEvent.LocalTrackPublished, roster)\n .on(RoomEvent.LocalTrackUnpublished, roster)\n // A SERVER DECISION CHANGED MID-MEETING (Meet wave 2): a co-host made or\n // unmade, the host handed over, a rename. The server re-stamps the\n // roster through `UpdateParticipant`; these three events carry it here.\n .on(RoomEvent.ParticipantNameChanged, roster)\n .on(RoomEvent.ParticipantAttributesChanged, roster)\n .on(RoomEvent.ParticipantMetadataChanged, roster)\n .on(RoomEvent.RoomMetadataChanged, (metadata) => {\n handlers.roomMetadata?.(metadata ?? \"\");\n })\n .on(RoomEvent.ActiveSpeakersChanged, (speakers) => {\n handlers.activeSpeakers(speakers.map((speaker) => speaker.identity));\n })\n .on(RoomEvent.ConnectionQualityChanged, (quality, participant) => {\n handlers.quality(participant.identity, mapQuality(quality));\n })\n .on(RoomEvent.ConnectionStateChanged, (state) => {\n handlers.connectionState(mapConnectionState(state));\n })\n .on(RoomEvent.DataReceived, (payload, participant, _kind, topic) => {\n handlers.data(\n topic ?? \"\",\n decoder.decode(payload),\n participant?.identity ?? null,\n );\n })\n .on(RoomEvent.Disconnected, (reason) => {\n handlers.disconnected(reason === undefined ? null : String(reason));\n });\n\n // LIVE CAPTIONS (D16). The agent publishes one text stream per utterance on\n // `lk.transcription`, re-sending the same `lk.segment_id` as the words firm\n // up, and the FINAL flag says which one is the last. The chunks are read as\n // they arrive — waiting for `readAll()` would make captions appear only\n // once the sentence was over, which is not a caption.\n //\n // 🚨 REGISTERED BEFORE `connect()`, deliberately: LiveKit buffers data\n // packets that arrive before the room is connected and replays them, but a\n // handler registered after the first stream header lands misses that\n // utterance outright — the first thing anyone says in the meeting.\n try {\n created.registerTextStreamHandler(TRANSCRIPTION_TOPIC, (reader, participantInfo) => {\n const attributes: Record<string, string> = { ...(reader.info.attributes ?? {}) };\n const segmentId =\n attributes[TRANSCRIPTION_ATTRIBUTES.segmentId] ?? reader.info.id;\n const trackId = attributes[TRANSCRIPTION_ATTRIBUTES.trackId] ?? null;\n const final = attributes[TRANSCRIPTION_ATTRIBUTES.final] === \"true\";\n // `lk.transcribed_participant_identity` is WHO IS BEING TRANSCRIBED.\n // The SFU's publisher identity stays the note-taker, so using it here\n // would attribute the whole meeting to the agent. Do not use the\n // sender-identity override: LiveKit accepts it from an agent publisher,\n // but aidream deliberately does not set it.\n const speakerIdentity =\n attributes[TRANSCRIPTION_ATTRIBUTES.speakerIdentity] ?? participantInfo.identity;\n const at = new Date(reader.info.timestamp || Date.now()).toISOString();\n void (async () => {\n let text = \"\";\n try {\n for await (const chunk of reader) {\n text += chunk;\n // Emit as it grows: a caption that only appears when the sentence\n // ends is a transcript, not a caption.\n handlers.transcription({\n segmentId,\n speakerIdentity,\n publisherIdentity: participantInfo.identity,\n text,\n final,\n trackId,\n at,\n });\n }\n } catch (error) {\n // A caption stream that dies is a caption we do not have. It is\n // never fatal to the meeting and never silent.\n handlers.data(\n TRANSCRIPTION_TOPIC,\n JSON.stringify({ error: String((error as Error)?.message ?? error) }),\n participantInfo.identity,\n );\n }\n })();\n });\n } catch {\n // Registering twice throws in the SDK. `load()` is single-flight through\n // `room`, so this can only happen on a re-entrant remount — in which case\n // the existing handler is already delivering captions.\n }\n\n // Kept for `attach`, which needs the SDK's Source enum at call time.\n sources = {\n camera: Track.Source.Camera,\n microphone: Track.Source.Microphone,\n screen: Track.Source.ScreenShare,\n };\n room = created;\n return created;\n }\n\n let sources: Record<DriverTrackKind, string> | null = null;\n\n function requireRoom(operation: string): Room {\n if (room === null) {\n throw new MeetError(\n \"transport\",\n `${operation}: the room is not connected`,\n \"Call connect() first. The engine never reaches this — it gates every media call \" +\n \"on its own phase — so seeing it means a consumer drove the driver directly.\",\n );\n }\n return room;\n }\n\n return {\n async connect(serverUrl, token) {\n const target = await load();\n try {\n await target.connect(serverUrl, token);\n } catch (error) {\n // A connect failure is either media permission (user-actionable) or\n // transport. Both must reach the UI with a sentence, never a spinner.\n throw normalizeDeviceError(error, \"meet.connect\");\n }\n // 🚨 PROJECT THE ROSTER ONCE, HERE. Every other roster source is an\n // EVENT, and a participant who publishes nothing into an empty room\n // generates none of them: no `LocalTrackPublished`, no\n // `ParticipantConnected`, no track events. Until 0.3.2 the join always\n // published a microphone, so `LocalTrackPublished` fired and hid this —\n // and the moment listen-only attendance became possible, a listen-only\n // host was absent from their own People panel, had no tile, and got NO\n // host controls at all (the note-taker could not be started), because\n // host powers are read off the local participant's roster entry.\n projectRoster?.();\n // The room's metadata arrives WITH the join (the spotlight lives there),\n // and `RoomMetadataChanged` fires only for later changes.\n handlers.roomMetadata?.(target.metadata ?? \"\");\n },\n async disconnect() {\n if (room === null) return;\n const target = room;\n room = null;\n try {\n target.unregisterTextStreamHandler(TRANSCRIPTION_TOPIC);\n } catch {\n // Already gone. Teardown is idempotent by contract.\n }\n projectRoster = null;\n await target.disconnect();\n },\n async setMicrophoneEnabled(enabled) {\n try {\n await requireRoom(\"setMicrophoneEnabled\").localParticipant.setMicrophoneEnabled(\n enabled,\n audioCapture,\n );\n } catch (error) {\n throw normalizeDeviceError(error, \"meet.setMicrophoneEnabled\");\n }\n },\n async setCameraEnabled(enabled) {\n try {\n const target = requireRoom(\"setCameraEnabled\");\n await target.localParticipant.setCameraEnabled(enabled);\n // A REMEMBERED EFFECT FOLLOWS THE CAMERA. Turning the camera back on must\n // not quietly show the room behind someone who chose to blur it.\n if (enabled && videoEffect.kind !== \"none\") await applyVideoEffect(target, videoEffect);\n } catch (error) {\n throw normalizeDeviceError(error, \"meet.setCameraEnabled\");\n }\n },\n async setScreenShareEnabled(enabled) {\n try {\n await requireRoom(\"setScreenShareEnabled\").localParticipant.setScreenShareEnabled(enabled);\n } catch (error) {\n throw normalizeDeviceError(error, \"meet.setScreenShareEnabled\");\n }\n },\n async publishData(topic, payload, to) {\n await requireRoom(\"publishData\").localParticipant.publishData(\n // `reliable` is not optional for a control plane: a dropped\n // \"hand lowered\" leaves a hand up on every other screen forever.\n encoder.encode(payload) as Uint8Array<ArrayBuffer>,\n to === undefined || to.length === 0\n ? { reliable: true, topic }\n : { reliable: true, topic, destinationIdentities: [...to] },\n );\n },\n async setAudioProcessing(processing) {\n audioCapture = { ...audioCapture, ...processing };\n const target = room;\n if (target === null) return;\n const { Track } = await import(\"livekit-client\");\n const publication = target.localParticipant.getTrackPublication(Track.Source.Microphone);\n const track = publication?.track;\n if (track === undefined || publication?.isMuted === true) return;\n try {\n // The browser's own processing, applied to the LIVE track: a restart\n // with new constraints, the same device, no renegotiation.\n await (track as unknown as { restartTrack(options: object): Promise<void> }).restartTrack({\n ...audioCapture,\n ...(target.getActiveDevice(\"audioinput\") !== undefined\n ? { deviceId: target.getActiveDevice(\"audioinput\") }\n : {}),\n });\n } catch (error) {\n throw normalizeDeviceError(error, \"meet.setAudioProcessing\");\n }\n },\n async setVideoEffect(effect) {\n videoEffect = effect;\n const target = room;\n if (target === null) return;\n await applyVideoEffect(target, effect);\n },\n supportsVideoEffects() {\n return videoEffectsSupported();\n },\n attach(identity, kind, element) {\n const target = requireRoom(\"attach\");\n const source = sources?.[kind];\n const participant =\n target.localParticipant.identity === identity\n ? target.localParticipant\n : target.remoteParticipants.get(identity);\n if (participant === undefined || source === undefined) return () => undefined;\n const publication = participant.getTrackPublication(source as never);\n const track = publication?.track;\n if (track === undefined) return () => undefined;\n track.attach(element);\n // The DETACH IS THE RETURN VALUE — a React effect's cleanup cannot forget\n // to call something it was handed.\n return () => {\n track.detach(element);\n };\n },\n activeDevices() {\n const target = room;\n if (target === null) {\n return { audioinput: null, videoinput: null, audiooutput: null };\n }\n return {\n audioinput: target.getActiveDevice(\"audioinput\") ?? null,\n videoinput: target.getActiveDevice(\"videoinput\") ?? null,\n audiooutput: target.getActiveDevice(\"audiooutput\") ?? null,\n };\n },\n async switchDevice(kind, deviceId) {\n try {\n await requireRoom(\"switchDevice\").switchActiveDevice(kind, deviceId);\n } catch (error) {\n throw normalizeDeviceError(error, \"meet.switchDevice\");\n }\n },\n };\n}\n\n/**\n * THE PRE-JOIN CAMERA PREVIEW (Meet wave 2) — the same SDK track and the same\n * background processor the room will use, so what someone sees before joining\n * is exactly what the meeting will see. Lives here because this file is the one\n * place `livekit-client` is touched.\n */\nexport interface CameraPreview {\n attach(element: HTMLVideoElement): void;\n setEffect(effect: VideoEffect): Promise<void>;\n stop(): void;\n}\n\nexport async function createCameraPreview(\n deviceId: string | null,\n effect: VideoEffect,\n): Promise<CameraPreview> {\n let module: typeof import(\"livekit-client\");\n try {\n module = await import(\"livekit-client\");\n } catch (error) {\n throw new MeetError(\n \"misconfigured\",\n \"livekit-client could not be loaded for the camera preview\",\n \"The bundler excluded `livekit-client`; remove it from any `external` list.\",\n error,\n );\n }\n let track: Awaited<ReturnType<typeof module.createLocalVideoTrack>>;\n try {\n track = await module.createLocalVideoTrack(deviceId === null ? {} : { deviceId });\n } catch (error) {\n throw normalizeDeviceError(error, \"meet.cameraPreview\");\n }\n const target = track as unknown as {\n setProcessor(processor: unknown): Promise<void>;\n stopProcessor(): Promise<void>;\n };\n async function apply(next: VideoEffect): Promise<void> {\n if (next.kind === \"none\") {\n await target.stopProcessor();\n return;\n }\n const processors = await import(\"@livekit/track-processors\");\n await target.setProcessor(\n next.kind === \"blur\"\n ? processors.BackgroundBlur(next.radius ?? 12)\n : processors.VirtualBackground(next.imageUrl),\n );\n }\n if (effect.kind !== \"none\" && videoEffectsSupported()) {\n try {\n await apply(effect);\n } catch {\n // The preview still shows the camera; the settings say the effect failed.\n }\n }\n return {\n attach(element) {\n track.attach(element);\n },\n setEffect: apply,\n stop() {\n track.stop();\n track.detach();\n },\n };\n}\n","\"use client\";\n\n/**\n * THE HOOKS. Thin shells over the framework-free core — every one of them\n * exists so a consumer never writes the sequence itself.\n *\n * The rule that shapes this file: a hook returns DATA and ACTIONS, never a\n * \"you must also call this on unmount\" instruction. `useTrack` hands back a ref\n * callback whose cleanup is the detach; `useRoom` disposes with the component.\n * A correct-usage checklist in a README is a bug waiting for a deadline.\n *\n * 🚨 **NO HOOK IN THIS FILE THROWS WHEN THE PROVIDER IS INERT** (0.2.1).\n * `<MeetProvider>` is deliberately inert until a client, an organization and an\n * identity are all real — which is EVERY server render, every signed-out\n * visitor, and every moment before the active organization hydrates. Through\n * 0.2.0 these hooks called `useRequiredMeetHost()`, so the exact three-line\n * integration the README prescribes returned a 500 on every route for every\n * such visitor, and the first real consumer had to wrap our own components in\n * a host-side guard (register MRI-D1). A hook now reports an inert runtime as\n * DATA — empty lists, `canCall: false`, `available: false` — so the components\n * above render nothing or an honest sentence on their own. Only an ACTION\n * invoked with no runtime fails, and it fails loudly with a remedy; it can not\n * be reached from a surface that renders correctly.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { MeetAnswerCoverage } from \"../core/ai\";\nimport { IDLE_MEDIA, listenOnlyNotice, type LocalMediaState } from \"../core/attendance\";\nimport { MeetError } from \"../core/errors\";\nimport {\n noteTakerLabel,\n noteTakerParticipant,\n noteTakerStatus,\n type NoteTakerStatus,\n} from \"../core/note-taker\";\nimport { displayNameFor, type NameBook } from \"../core/names\";\nimport { readableTranscript } from \"../core/transcript\";\n\n/** A stable empty book, so `useMemo` does not re-run on every render. */\nconst EMPTY_NAMES: NameBook = {};\nimport { END_MEETING_NOT_SERVED } from \"../core/meetings\";\nimport { computeStage, DEFAULT_PAGE_SIZE, type Stage } from \"../core/layout\";\nimport { canModerateParticipant } from \"../core/meetings\";\nimport { isRecordingInFlight, recordingLabel } from \"../core/recording\";\nimport type { MeetingSession } from \"../core/meetings\";\nimport type { JoinRequest, RoomEngine } from \"../core/room\";\nimport type { ModerationRequest, ModerationResult } from \"../core/in-room\";\nimport {\n DEFAULT_EFFECTS,\n REACTION_TTL_MS,\n type MediaEffects,\n type ModerationNotice,\n} from \"../core/store\";\nimport { isHostRole } from \"../core/types\";\nimport {\n guestRecordAccessSetting,\n activeWrapUpSummary,\n loadGuestMeetingRecord,\n loadMeetingRecord,\n setGuestRecordAccess,\n type GuestRecordAccessResolution,\n type GuestRecordAccessSetting,\n type MeetingRecordBundle,\n} from \"../core/record\";\nimport type {\n CallInvite,\n CallMode,\n LobbyEntry,\n MeetParticipant,\n MeetingId,\n MeetingNote,\n MeetingRecord,\n ParticipantIdentity,\n RoomName,\n StageLayout,\n TranscriptSource,\n UserId,\n WrapUpAnnouncement,\n} from \"../core/types\";\nimport {\n useCanRecord,\n useIsHost,\n useRole,\n useMeetHost,\n useMeetSnapshot,\n type MeetHost,\n} from \"./provider\";\n\n/**\n * The ONE sentence every hook says when an action is invoked with no runtime.\n * It names the state and the fix; it never returns a silent no-op, because a\n * button that quietly does nothing is the failure this package exists to avoid.\n */\nconst NO_RUNTIME_REMEDY =\n \"Render this inside a <MeetProvider> that has a Supabase client, an organization id and \" +\n \"an identity (userId or guestName). The provider stays inert until all three are real, \" +\n \"and while it is inert this package's components render nothing rather than a dead control.\";\n\nfunction noRuntime(action: string): MeetError {\n return new MeetError(\n \"misconfigured\",\n `[@ai-matrx/meet] ${action}: there is no meet runtime on this tree.`,\n NO_RUNTIME_REMEDY,\n );\n}\n\nfunction requireHost(host: MeetHost | null, action: string): MeetHost {\n if (host === null) throw noRuntime(action);\n return host;\n}\n\nfunction requireEngine(engine: RoomEngine | null, action: string): RoomEngine {\n if (engine === null) throw noRuntime(action);\n return engine;\n}\n\nfunction requireSession(session: MeetingSession | null, action: string): MeetingSession {\n if (session === null) throw noRuntime(action);\n return session;\n}\n\nexport interface UseRoomResult {\n readonly phase: string;\n readonly participants: readonly MeetParticipant[];\n readonly failure: { readonly message: string; readonly remedy: string } | null;\n join: (request: JoinRequest) => Promise<void>;\n leave: () => Promise<void>;\n toggleMicrophone: () => Promise<void>;\n toggleCamera: () => Promise<void>;\n toggleScreenShare: () => Promise<void>;\n toggleHand: () => Promise<void>;\n react: (emoji: string) => Promise<void>;\n /** To EVERYONE — saved through the server (Meet wave 2). */\n sendChat: (text: string) => Promise<void>;\n /** To ONE person — data plane only, never saved. */\n sendPrivateChat: (to: ParticipantIdentity, text: string) => Promise<void>;\n pin: (identity: ParticipantIdentity | null) => void;\n setLayout: (layout: StageLayout) => void;\n readonly local: MeetParticipant | null;\n}\n\nexport function useRoom(): UseRoomResult {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const engine = host?.engine ?? null;\n\n const local =\n snapshot?.participants.find(\n (participant) => participant.identity === snapshot.localIdentity,\n ) ?? null;\n\n return {\n phase: snapshot?.phase ?? \"idle\",\n participants: snapshot?.participants ?? [],\n failure: snapshot?.failure ?? null,\n local,\n join: useCallback(\n async (request: JoinRequest) => requireEngine(engine, \"join\").join(request),\n [engine],\n ),\n leave: useCallback(async () => requireEngine(engine, \"leave\").leave(), [engine]),\n toggleMicrophone: useCallback(\n async () =>\n requireEngine(engine, \"toggleMicrophone\").setMicrophoneEnabled(\n !(local?.micEnabled ?? false),\n ),\n [engine, local],\n ),\n toggleCamera: useCallback(\n async () =>\n requireEngine(engine, \"toggleCamera\").setCameraEnabled(!(local?.cameraEnabled ?? false)),\n [engine, local],\n ),\n toggleScreenShare: useCallback(\n async () =>\n requireEngine(engine, \"toggleScreenShare\").setScreenShareEnabled(\n !(local?.screenSharing ?? false),\n ),\n [engine, local],\n ),\n toggleHand: useCallback(\n async () => requireEngine(engine, \"toggleHand\").raiseHand(!(local?.handRaised ?? false)),\n [engine, local],\n ),\n react: useCallback(\n async (emoji: string) => requireEngine(engine, \"react\").react(emoji),\n [engine],\n ),\n sendChat: useCallback(\n async (text: string) => {\n if (host === null) throw noRuntime(\"sendChat\");\n await host.inRoom.sendChat(text);\n },\n [host],\n ),\n sendPrivateChat: useCallback(\n async (to: ParticipantIdentity, text: string) =>\n requireEngine(engine, \"sendPrivateChat\").sendPrivateChat(to, text),\n [engine],\n ),\n pin: useCallback(\n (identity: ParticipantIdentity | null) => requireEngine(engine, \"pin\").pin(identity),\n [engine],\n ),\n setLayout: useCallback(\n (layout: StageLayout) => requireEngine(engine, \"setLayout\").setLayout(layout),\n [engine],\n ),\n };\n}\n\n/** The stage, recomputed only when the roster or the layout actually changes. */\nexport function useStage(pageSize = DEFAULT_PAGE_SIZE): Stage {\n const snapshot = useMeetSnapshot();\n const [page, setPage] = useState(0);\n const stage = useMemo(\n () =>\n computeStage({\n participants: snapshot?.participants ?? [],\n layout: snapshot?.layout ?? \"grid\",\n pinned: snapshot?.pinned ?? null,\n spotlight: snapshot?.spotlight ?? null,\n activeSpeakers: snapshot?.activeSpeakers ?? [],\n pageSize,\n page,\n }),\n [snapshot, pageSize, page],\n );\n // Clamp back into range when people leave — a page that scrolled past the\n // end must not render an empty stage.\n useEffect(() => {\n if (page > stage.pageCount - 1) setPage(Math.max(0, stage.pageCount - 1));\n }, [page, stage.pageCount]);\n return stage;\n}\n\n/**\n * Attach a participant's media to an element. The returned ref callback's\n * CLEANUP is the detach — there is nothing a consumer can forget to call.\n */\nexport function useTrack(\n identity: ParticipantIdentity | null,\n kind: \"camera\" | \"microphone\" | \"screen\",\n): (element: HTMLMediaElement | null) => void {\n const host = useMeetHost();\n const detachRef = useRef<(() => void) | null>(null);\n return useCallback(\n (element: HTMLMediaElement | null) => {\n detachRef.current?.();\n detachRef.current = null;\n if (element === null || identity === null || host === null) return;\n detachRef.current = host.engine.attach(identity, kind, element);\n },\n [host, identity, kind],\n );\n}\n\nexport interface UseCallsResult {\n readonly incoming: readonly CallInvite[];\n readonly outgoing: CallInvite | null;\n /** `null` for a guest identity — the UI renders nothing rather than a dead button. */\n readonly canCall: boolean;\n call: (people: readonly UserId[], mode: CallMode) => Promise<CallInvite>;\n accept: (invite: CallInvite) => Promise<void>;\n decline: (invite: CallInvite, message?: string) => Promise<void>;\n cancel: (invite: CallInvite) => Promise<void>;\n}\n\nexport function useCalls(): UseCallsResult {\n // NOT `useRequiredMeetHost`. `<IncomingCallHost/>` is mounted app-wide by\n // contract, so it renders on every server render and for every signed-out\n // visitor — states in which this provider is correctly inert.\n const host = useMeetHost();\n const center = host?.calls ?? null;\n const [, force] = useState(0);\n\n // The call center is not a store (it is a lifecycle object), so a ring must\n // re-render this hook. A 500ms poll would be a lie about liveness; the\n // provider's onIncoming already fires, so we re-render on the same tick.\n useEffect(() => {\n if (center === null) return undefined;\n const timer = setInterval(() => force((value) => value + 1), 1_000);\n return () => clearInterval(timer);\n }, [center]);\n\n return {\n incoming: center?.incoming() ?? [],\n outgoing: center?.outgoing() ?? null,\n canCall: center !== null,\n call: useCallback(\n async (people: readonly UserId[], mode: CallMode) => {\n if (center === null) {\n throw noRuntime(\n host === null ? \"call\" : \"call (a guest identity has no calling surface, D6)\",\n );\n }\n const invite = await center.call({ people, mode });\n force((value) => value + 1);\n return invite;\n },\n [center, host],\n ),\n accept: useCallback(\n async (invite: CallInvite) => {\n if (center === null || host === null) return;\n await center.accept(invite.id, invite.mode);\n await host.engine.join({ roomName: invite.roomName, mode: invite.mode });\n force((value) => value + 1);\n },\n [center, host],\n ),\n decline: useCallback(\n async (invite: CallInvite, message?: string) => {\n if (center === null) return;\n await center.decline(invite.id, message);\n force((value) => value + 1);\n },\n [center],\n ),\n cancel: useCallback(\n async (invite: CallInvite) => {\n if (center === null) return;\n await center.cancel(invite.id);\n force((value) => value + 1);\n },\n [center],\n ),\n };\n}\n\nexport interface UseLobbyResult {\n readonly waiting: readonly LobbyEntry[];\n readonly canAdmit: boolean;\n admit: (entry: LobbyEntry) => Promise<void>;\n deny: (entry: LobbyEntry) => Promise<void>;\n admitAll: () => Promise<void>;\n knock: (roomName: RoomName) => void;\n}\n\nexport function useLobby(): UseLobbyResult {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const isHost = useIsHost();\n const session = host?.meetings ?? null;\n return {\n waiting: (snapshot?.lobby ?? []).filter((entry) => entry.state === \"knocking\"),\n // No runtime means no host powers — `<LobbyPanel>` renders nothing rather\n // than an admit button that would throw.\n canAdmit: session !== null && isHost,\n admit: useCallback(\n async (entry: LobbyEntry) => requireSession(session, \"admit\").admit(entry, true),\n [session],\n ),\n deny: useCallback(\n async (entry: LobbyEntry) => requireSession(session, \"deny\").admit(entry, false),\n [session],\n ),\n admitAll: useCallback(\n async () => requireSession(session, \"admitAll\").admitAll(),\n [session],\n ),\n knock: useCallback(\n (roomName: RoomName) => requireSession(session, \"knock\").knock(roomName),\n [session],\n ),\n };\n}\n\nexport interface UseRecordingResult {\n readonly state: string;\n readonly label: string | null;\n readonly canStart: boolean;\n readonly canStop: boolean;\n readonly consentNotice: string | null;\n start: () => Promise<void>;\n stop: () => Promise<void>;\n}\n\nexport function useRecording(): UseRecordingResult {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n // 🚨 THE SERVER'S GRANT, not `isHost` (MRI-A11). aidream computes\n // `can_record = is_host AND policy == host-controlled` and puts it on the\n // token and the roster attribute; the policy half is why a host of an\n // `always-on` meeting correctly gets NO control. The policy check below is\n // kept as the package's own agreement with that rule, never as a substitute.\n const canRecord = useCanRecord();\n const meeting = snapshot?.meeting ?? null;\n const state = snapshot?.recording ?? \"idle\";\n // 🚨 NOT `state === \"idle\"` (MRI-A16). Once the durable states actually\n // arrive, a meeting whose recording finished sits on `available`, and asking\n // for `idle` made the Start control vanish for the rest of the session.\n const canStart =\n host !== null && canRecord && host.recording.canStart(meeting, true) && !isRecordingInFlight(state);\n\n return {\n state,\n label: recordingLabel(state),\n canStart,\n // `stopping` is already stopping; the other in-flight states can be.\n canStop: host !== null && canRecord && (state === \"recording\" || state === \"starting\"),\n consentNotice: host?.recording.consentNotice(meeting) ?? null,\n start: useCallback(async () => {\n const live = requireHost(host, \"startRecording\");\n if (meeting === null || live.identity.userId === null) return;\n await live.recording.start({\n meetingId: meeting.id,\n roomName: meeting.roomName,\n by: live.identity.userId,\n });\n }, [host, meeting]),\n stop: useCallback(async () => {\n const live = requireHost(host, \"stopRecording\");\n if (meeting === null || live.identity.userId === null) return;\n await live.recording.stop({ meetingId: meeting.id, by: live.identity.userId });\n }, [host, meeting]),\n };\n}\n\n/** One line of the transcript, as a panel renders it. */\nexport interface TranscriptLine {\n readonly id: string;\n /** Who said it, as the room knows them. Surfaces group by THIS, not by name. */\n readonly identity: ParticipantIdentity;\n readonly speaker: string;\n readonly text: string;\n readonly final: boolean;\n /** `caption` is a live hint; `record` is the durable transcript (D16). */\n readonly source: TranscriptSource;\n}\n\nexport interface UseMeetAiResult {\n /** The note-taker's honest state, and the server's refusal if there was one. */\n readonly noteTaker: NoteTakerStatus;\n /** The sentence for that state. Never a bare enum, never a spinner. */\n readonly noteTakerLabel: string;\n /** True only for a host of a meeting whose AI is on. Guests get no control. */\n readonly canControlNoteTaker: boolean;\n /** Live-window notes, oldest first. */\n readonly notes: readonly MeetingNote[];\n readonly decisions: readonly MeetingNote[];\n readonly actionItems: readonly MeetingNote[];\n /** The wrap-up summary, once the meeting has produced one. */\n readonly summary: MeetingNote | null;\n /**\n * The wrap-up pass ANNOUNCED itself into this room (MRI-A12). `null` means it\n * has not been announced HERE — never that no summary exists. The ordinary\n * ending path deletes the LiveKit room before the pass runs, so this is\n * normally null and the summary is read on the post-meeting record.\n */\n readonly wrapUp: WrapUpAnnouncement | null;\n readonly transcript: readonly TranscriptLine[];\n readonly asking: boolean;\n /** The answer SO FAR. It grows while the answer streams. */\n readonly answer: string | null;\n readonly coverage: MeetAnswerCoverage | null;\n /** The server's phase while an answer is being built. */\n readonly phase: string | null;\n readonly error: { readonly message: string; readonly remedy: string } | null;\n ask: (question: string) => Promise<void>;\n startNoteTaker: () => Promise<void>;\n stopNoteTaker: () => Promise<void>;\n}\n\n/**\n * THE MEETING ASSISTANT, as a surface needs it.\n *\n * Everything below is DATA, including every failure. There is no state in which\n * this hook returns a spinner with nothing behind it: the note-taker is in one\n * of five named states or the server refused with a sentence, and an answer is\n * either arriving (visibly, token by token) or has failed with a remedy.\n */\nexport function useMeetAi(): UseMeetAiResult {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const isHost = useIsHost();\n const [asking, setAsking] = useState(false);\n const [answer, setAnswer] = useState<string | null>(null);\n const [coverage, setCoverage] = useState<MeetAnswerCoverage | null>(null);\n const [phase, setPhase] = useState<string | null>(null);\n const [error, setError] = useState<{ message: string; remedy: string } | null>(null);\n const ai = host?.ai ?? null;\n const meeting = snapshot?.meeting ?? null;\n const participants = snapshot?.participants ?? [];\n const notes = snapshot?.notes ?? [];\n const wrapUp = snapshot?.wrapUp ?? null;\n\n const status = useMemo(\n () =>\n noteTakerStatus({\n meeting,\n participants,\n refusal: snapshot?.noteTakerRefusal ?? null,\n }),\n [meeting, participants, snapshot?.noteTakerRefusal],\n );\n\n const names = snapshot?.names ?? EMPTY_NAMES;\n const transcript = useMemo(\n () =>\n readableTranscript(snapshot?.transcript ?? []).map((line) => ({\n id: line.id,\n identity: line.identity,\n // 🚨 RESOLVED, not rendered raw (MRI-A16). A line stamped before its\n // speaker's name was known — a durable row that beat the roster, a\n // caption from someone who has since left — is re-attributed the moment\n // anything learns the name, in BOTH lanes, so the host and the guest\n // never read two different names for one speaker again (MRI-C8).\n speaker: displayNameFor(names, line.identity, line.speaker),\n text: line.text,\n final: line.final,\n source: line.source,\n })),\n [snapshot?.transcript, names],\n );\n\n const dispatchNoteTaker = useCallback(\n async (run: () => Promise<unknown>) => {\n setError(null);\n try {\n await run();\n } catch (thrown) {\n // THE SERVER'S SENTENCE REACHES THE SCREEN. A dispatch that failed and\n // said nothing is a meeting everyone believes is being minuted.\n setError({\n message: (thrown as Error).message,\n remedy:\n (thrown as { remedy?: string }).remedy ??\n \"The note-taker action could not be confirmed. Check its current state and try again.\",\n });\n }\n },\n [],\n );\n\n return {\n noteTaker: status,\n noteTakerLabel: noteTakerLabel(status),\n // A guest cannot dispatch an agent, and neither can anyone in a meeting\n // whose AI is off. The control is ABSENT for them, never disabled-looking.\n canControlNoteTaker:\n ai !== null && meeting !== null && meeting.aiEnabled && isHost && host?.identity.userId !== null,\n notes: notes.filter((note) => note.kind === \"note\" && note.role === null),\n // D20: the wrap-up is the authoritative post-meeting set. A window-written\n // decision the wrap-up superseded stays in `notes` — the timeline — and is\n // not listed a second time as a decision that was made.\n decisions: notes.filter((note) => note.kind === \"decision\" && note.supersededBy === null),\n actionItems: notes.filter(\n (note) => note.kind === \"action-item\" && note.supersededBy === null,\n ),\n summary: activeWrapUpSummary(notes),\n wrapUp,\n transcript,\n asking,\n answer,\n coverage,\n phase,\n error,\n ask: useCallback(\n async (question: string) => {\n if (ai === null || meeting === null) return;\n setAsking(true);\n setError(null);\n setAnswer(null);\n setCoverage(null);\n setPhase(null);\n try {\n const result = await ai.ask({\n meetingId: meeting.id,\n question,\n // THE ANSWER RENDERS AS IT ARRIVES. Waiting for the last token to\n // show the first is a spinner wearing an answer's clothes.\n onText: (text) => setAnswer(text),\n onPhase: (value) => setPhase(value),\n });\n setAnswer(result.text);\n setCoverage(result.coverage);\n } catch (thrown) {\n setError({\n message: (thrown as Error).message,\n remedy:\n (thrown as { remedy?: string }).remedy ??\n \"The assistant could not answer. Nothing was changed by the attempt.\",\n });\n } finally {\n setAsking(false);\n setPhase(null);\n }\n },\n [ai, meeting],\n ),\n startNoteTaker: useCallback(async () => {\n if (ai === null || meeting === null) return;\n await dispatchNoteTaker(() =>\n ai.startNoteTaker({ meetingId: meeting.id, roomName: meeting.roomName }),\n );\n }, [ai, meeting, dispatchNoteTaker]),\n stopNoteTaker: useCallback(async () => {\n if (ai === null || meeting === null) return;\n await dispatchNoteTaker(() => ai.stopNoteTaker({ meetingId: meeting.id }));\n }, [ai, meeting, dispatchNoteTaker]),\n };\n}\n\n/**\n * ENDING THE MEETING FOR EVERYONE — a host control with an honest failure.\n *\n * `POST /v1/meet/end` is served by MRI-A6. A server that has not landed it\n * answers 404, and this hook reports that as the sentence\n * `END_MEETING_NOT_SERVED` rather than pretending the meeting ended or leaving\n * a button that appears to do nothing.\n */\nexport interface UseEndMeetingResult {\n readonly canEnd: boolean;\n readonly ending: boolean;\n readonly ended: boolean;\n /** The honest sentence when the attempt did not end the meeting. */\n readonly notice: string | null;\n end: () => Promise<void>;\n}\n\nexport function useEndMeeting(): UseEndMeetingResult {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const isHost = useIsHost();\n const [ending, setEnding] = useState(false);\n const [notice, setNotice] = useState<string | null>(null);\n const meeting = snapshot?.meeting ?? null;\n const session = host?.meetings ?? null;\n\n return {\n canEnd: session !== null && isHost && meeting !== null && meeting.endedAt === null,\n ending,\n ended: meeting?.endedAt !== null && meeting?.endedAt !== undefined,\n notice,\n end: useCallback(async () => {\n const live = requireSession(session, \"endForEveryone\");\n setEnding(true);\n setNotice(null);\n try {\n const result = await live.endForEveryone();\n if (!result.served) {\n // NOT A DEAD BUTTON AND NOT A LIE: the route is pinned in the\n // package's contract and this server has not landed it yet (MRI-A6).\n setNotice(END_MEETING_NOT_SERVED);\n }\n } catch (thrown) {\n const remedy = (thrown as { remedy?: string }).remedy;\n setNotice(\n remedy !== undefined\n ? `${(thrown as Error).message} ${remedy}`\n : (thrown as Error).message,\n );\n } finally {\n setEnding(false);\n }\n }, [session]),\n };\n}\n\n/**\n * THE CONSENT NOTICE (D10) — a property of this package, never a prop.\n *\n * Returns the sentence every participant must see while an agent is in the\n * room, or `null` when none is. There is deliberately no way to turn it off:\n * the org's policy decides whether a note-taker may run, and it never decides\n * whether the people in the room are told about it.\n */\nexport function useConsentNotice(): string | null {\n const snapshot = useMeetSnapshot();\n const agent = noteTakerParticipant(snapshot?.participants ?? []);\n if (agent === null) return null;\n return (\n `${agent.displayName} is in this meeting: it is transcribing what is said and ` +\n \"writing notes everyone here can read.\"\n );\n}\n\n/**\n * What the LOCAL participant is actually publishing, and why not when it is not.\n * Read this — never the roster's `micEnabled` — to decide whether to tell\n * someone they cannot be heard: the roster reflects the media plane, this\n * reflects the ATTEMPT, including one the browser refused outright (there is no\n * track to be un-muted in that case, so the roster would simply say `false`\n * with no reason attached).\n */\nexport function useLocalMedia(): LocalMediaState {\n const snapshot = useMeetSnapshot();\n return snapshot?.media ?? IDLE_MEDIA;\n}\n\n/**\n * The listen-only sentence, or `null` while the microphone is live. The remedy,\n * when the device was refused rather than declined, is on\n * `useLocalMedia().microphone.unavailable`.\n */\nexport function useListenOnlyNotice(): string | null {\n return listenOnlyNotice(useLocalMedia());\n}\n\n/** Live reactions, already expired. Rendering stale confetti is the alternative. */\nexport function useReactions(): readonly { id: string; emoji: string }[] {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const store = host?.store ?? null;\n useEffect(() => {\n if (store === null) return undefined;\n const timer = setInterval(() => store.expireReactions(Date.now()), REACTION_TTL_MS / 2);\n return () => clearInterval(timer);\n }, [store]);\n return snapshot?.reactions ?? [];\n}\n\n/** A ticking duration for the call header. One timer, not one per component. */\nexport function useElapsed(startedAt: string | null): number {\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n if (startedAt === null) return undefined;\n const timer = setInterval(() => setNow(Date.now()), 1_000);\n return () => clearInterval(timer);\n }, [startedAt]);\n if (startedAt === null) return 0;\n return Math.max(0, now - Date.parse(startedAt));\n}\n\n/** Whether the local actor may moderate a given participant. One rank check. */\nexport function useCanModerate(target: MeetParticipant | undefined): boolean {\n const snapshot = useMeetSnapshot();\n const role = useRole();\n const me = snapshot?.participants.find(\n (participant) => participant.identity === snapshot.localIdentity,\n );\n // The EFFECTIVE role (token ∪ roster attribute — MRI-A11), not whichever of\n // the two the roster happened to carry this tick.\n return canModerateParticipant(me === undefined ? undefined : { ...me, role }, target);\n}\n\n/**\n * 🚨 EVERY HOST POWER, THROUGH THE SERVER (MRI-A11 → Meet wave 2).\n *\n * `canModerate` is the rank check — a host outranks a co-host outranks\n * everyone, and NOBODY may moderate themselves — so a surface renders a control\n * only where it would actually be honoured. The act itself is a server call\n * (`core/in-room.ts`): through 0.7.x mute and remove were data packets nothing\n * listened to, which made them buttons that did nothing.\n *\n * `notice` is the server's last sentence (or refusal) for the actor — a control\n * that acted and said nothing is indistinguishable from one that did nothing.\n */\nexport interface UseHostControlsResult {\n readonly isHost: boolean;\n /** The host itself (not a co-host) — only the host hands the meeting over. */\n readonly isOwner: boolean;\n readonly notice: { readonly text: string; readonly failed: boolean } | null;\n readonly busy: boolean;\n clearNotice: () => void;\n canModerate: (target: MeetParticipant) => boolean;\n run: (request: ModerationRequest) => Promise<ModerationResult | null>;\n mute: (target: MeetParticipant) => Promise<void>;\n remove: (target: MeetParticipant) => Promise<void>;\n}\n\nexport function useHostControls(): UseHostControlsResult {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const role = useRole();\n const me = snapshot?.participants.find(\n (participant) => participant.identity === snapshot.localIdentity,\n );\n const actor = me === undefined ? undefined : { ...me, role };\n const [busy, setBusy] = useState(false);\n const inRoom = host?.inRoom ?? null;\n const store = host?.store ?? null;\n const notice = snapshot?.actionNotice ?? null;\n const setNotice = useCallback(\n (next: { text: string; failed: boolean } | null) =>\n store?.patch({ actionNotice: next === null ? null : { ...next, at: Date.now() } }),\n [store],\n );\n\n const run = useCallback(\n async (request: ModerationRequest): Promise<ModerationResult | null> => {\n if (inRoom === null) throw noRuntime(`moderate(${request.action})`);\n setBusy(true);\n try {\n const result = await inRoom.moderate(request);\n setNotice({ text: result.message, failed: false });\n return result;\n } catch (thrown) {\n const error = thrown as { message?: string; remedy?: string };\n setNotice({\n text: [error.message, error.remedy].filter(Boolean).join(\" \"),\n failed: true,\n });\n return null;\n } finally {\n setBusy(false);\n }\n },\n [inRoom, setNotice],\n );\n\n return {\n isHost: isHostRole(role),\n isOwner: role === \"host\",\n notice,\n busy,\n clearNotice: useCallback(() => setNotice(null), [setNotice]),\n canModerate: useCallback(\n (target: MeetParticipant) => canModerateParticipant(actor, target),\n [actor],\n ),\n run,\n mute: useCallback(\n async (target: MeetParticipant) => {\n await run({ action: \"mute\", identity: target.identity });\n },\n [run],\n ),\n remove: useCallback(\n async (target: MeetParticipant) => {\n await run({ action: \"remove\", identity: target.identity });\n },\n [run],\n ),\n };\n}\n\n/**\n * THE HAND QUEUE — raised hands in the order they went up (Meet wave 2).\n * First raised, first called on; a late joiner learns the order from each\n * client's re-announcement (`room.ts`).\n */\nexport function useHandQueue(): readonly MeetParticipant[] {\n const snapshot = useMeetSnapshot();\n return useMemo(\n () =>\n (snapshot?.participants ?? [])\n .filter((participant) => participant.handRaised)\n .sort((a, b) => (a.handRaisedAt ?? 0) - (b.handRaisedAt ?? 0)),\n [snapshot?.participants],\n );\n}\n\n/** This participant's noise suppression and background, and the setter. */\nexport interface UseMediaEffectsResult {\n readonly effects: MediaEffects;\n /** False = this browser cannot run a background effect; the control is absent. */\n readonly backgroundsSupported: boolean;\n set: (next: Partial<MediaEffects>) => Promise<void>;\n}\n\nexport function useMediaEffects(): UseMediaEffectsResult {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const engine = host?.engine ?? null;\n return {\n effects: snapshot?.effects ?? DEFAULT_EFFECTS,\n backgroundsSupported: engine?.supportsVideoEffects() ?? false,\n set: useCallback(\n async (next: Partial<MediaEffects>) => requireEngine(engine, \"setEffects\").setEffects(next),\n [engine],\n ),\n };\n}\n\n/** What a host last did to THIS participant, and a way to dismiss it. */\nexport function useModerationNotice(): { notice: ModerationNotice | null; dismiss: () => void } {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n return {\n notice: snapshot?.moderationNotice ?? null,\n dismiss: useCallback(() => host?.store.patch({ moderationNotice: null }), [host]),\n };\n}\n\n/**\n * A live microphone level, 0..1, for a meter. Reads the given stream through an\n * `AnalyserNode`; returns 0 while there is none. One animation frame loop,\n * closed with the stream.\n */\nexport function useAudioLevel(stream: MediaStream | null): number {\n const [level, setLevel] = useState(0);\n useEffect(() => {\n if (stream === null || stream.getAudioTracks().length === 0) {\n setLevel(0);\n return undefined;\n }\n const Context =\n (globalThis as { AudioContext?: typeof AudioContext }).AudioContext ??\n (globalThis as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (Context === undefined) return undefined;\n const context = new Context();\n const source = context.createMediaStreamSource(stream);\n const analyser = context.createAnalyser();\n analyser.fftSize = 512;\n source.connect(analyser);\n const samples = new Uint8Array(analyser.fftSize);\n let frame = 0;\n const tick = () => {\n analyser.getByteTimeDomainData(samples);\n let peak = 0;\n for (const sample of samples) peak = Math.max(peak, Math.abs(sample - 128) / 128);\n setLevel((previous) => (Math.abs(previous - peak) > 0.02 ? peak : previous));\n frame = requestAnimationFrame(tick);\n };\n frame = requestAnimationFrame(tick);\n return () => {\n cancelAnimationFrame(frame);\n source.disconnect();\n void context.close();\n };\n }, [stream]);\n return level;\n}\n\n/**\n * THE KEYBOARD SHORTCUTS (Meet wave 2) — Google Meet's own chords, so nobody\n * relearns anything: ⌘/Ctrl+D mute, ⌘/Ctrl+E camera, ⌘/Ctrl+Alt+H hand,\n * ⌘/Ctrl+Alt+C chat, ⌘/Ctrl+Alt+P people, Shift+? the shortcuts sheet. Never\n * fires while the person is typing in a field.\n */\nexport const MEET_SHORTCUTS: readonly {\n readonly id: \"mic\" | \"camera\" | \"hand\" | \"chat\" | \"people\" | \"help\";\n readonly keys: string;\n readonly label: string;\n}[] = [\n { id: \"mic\", keys: \"⌘/Ctrl + D\", label: \"Mute or unmute your microphone\" },\n { id: \"camera\", keys: \"⌘/Ctrl + E\", label: \"Turn your camera on or off\" },\n { id: \"hand\", keys: \"⌘/Ctrl + Alt + H\", label: \"Raise or lower your hand\" },\n { id: \"chat\", keys: \"⌘/Ctrl + Alt + C\", label: \"Open or close chat\" },\n { id: \"people\", keys: \"⌘/Ctrl + Alt + P\", label: \"Open or close people\" },\n { id: \"help\", keys: \"Shift + ?\", label: \"Show keyboard shortcuts\" },\n];\n\nexport function useMeetShortcuts(\n handlers: Partial<Record<(typeof MEET_SHORTCUTS)[number][\"id\"], () => void>>,\n): void {\n const ref = useRef(handlers);\n ref.current = handlers;\n useEffect(() => {\n const target = (globalThis as { window?: Window }).window;\n if (target === undefined) return undefined;\n const onKey = (event: KeyboardEvent) => {\n const element = event.target as HTMLElement | null;\n const typing =\n element !== null &&\n (element.isContentEditable ||\n element.tagName === \"INPUT\" ||\n element.tagName === \"TEXTAREA\" ||\n element.tagName === \"SELECT\");\n const mod = event.metaKey || event.ctrlKey;\n const key = event.key.toLowerCase();\n let id: (typeof MEET_SHORTCUTS)[number][\"id\"] | null = null;\n if (mod && !event.altKey && !event.shiftKey && key === \"d\") id = \"mic\";\n else if (mod && !event.altKey && !event.shiftKey && key === \"e\") id = \"camera\";\n else if (mod && event.altKey && (event.code === \"KeyH\" || key === \"h\")) id = \"hand\";\n else if (mod && event.altKey && (event.code === \"KeyC\" || key === \"c\")) id = \"chat\";\n else if (mod && event.altKey && (event.code === \"KeyP\" || key === \"p\")) id = \"people\";\n else if (!mod && !typing && event.key === \"?\") id = \"help\";\n if (id === null) return;\n const handler = ref.current[id];\n if (handler === undefined) return;\n // ⌘D is \"bookmark\" and ⌘E is \"search\" in browsers: the meeting wins while\n // it is on screen, exactly as it does in Meet.\n event.preventDefault();\n handler();\n };\n target.addEventListener(\"keydown\", onKey);\n return () => target.removeEventListener(\"keydown\", onKey);\n }, []);\n}\n\nexport function useMeeting(): MeetingRecord | null {\n return useMeetSnapshot()?.meeting ?? null;\n}\n\nexport function useMeetingId(): MeetingId | null {\n return useMeetSnapshot()?.meeting?.id ?? null;\n}\n\n/* ------------------------------------------------------ the meeting record */\n\n/**\n * THE MEETING AFTER THE MEETING (MRI-D2).\n *\n * A durable link outlives the room (R3), and until this hook existed it\n * resolved to a pre-join screen for a room nobody could enter — the summary,\n * decisions, action items, live notes, transcript and recording were reachable\n * only from SQL. This loads all of it from durable rows, states what the reader\n * is not allowed to see instead of rendering emptiness, and keeps the Q&A box\n * working against the record: `/intelligence/ask` reads the same durable rows\n * and answers a signed-in member long after the room closed.\n *\n * It is deliberately independent of the room store: nothing here needs a\n * LiveKit connection, a token, or a joined participant.\n */\nexport interface UseMeetingRecordResult {\n readonly loading: boolean;\n readonly record: MeetingRecordBundle | null;\n /** A failure that stopped the WHOLE record loading. Partial refusals are in\n * `record.restrictions` — this is null whenever a record exists. */\n readonly failure: { readonly message: string; readonly remedy: string } | null;\n /** Q&A against the durable record. Streams, exactly as it does in-room. */\n readonly asking: boolean;\n readonly answer: string | null;\n readonly coverage: MeetAnswerCoverage | null;\n readonly askError: { readonly message: string; readonly remedy: string } | null;\n ask: (question: string) => Promise<void>;\n reload: () => void;\n}\n\nexport function useMeetingRecord(meeting: MeetingRecord | null): UseMeetingRecordResult {\n const host = useMeetHost();\n const repository = host?.repository ?? null;\n const ai = host?.ai ?? null;\n const readerId = host?.identity.userId ?? null;\n const [recordReaderId, setRecordReaderId] = useState<typeof readerId>(readerId);\n const [record, setRecord] = useState<MeetingRecordBundle | null>(null);\n const [loading, setLoading] = useState(true);\n const [failure, setFailure] = useState<{ message: string; remedy: string } | null>(null);\n const [nonce, setNonce] = useState(0);\n const [asking, setAsking] = useState(false);\n const [answer, setAnswer] = useState<string | null>(null);\n const [coverage, setCoverage] = useState<MeetAnswerCoverage | null>(null);\n const [askError, setAskError] = useState<{ message: string; remedy: string } | null>(null);\n\n const meetingId = meeting?.id ?? null;\n\n const api = host?.api ?? null;\n const tokens = host?.tokens ?? null;\n const roomName = meeting?.roomName ?? null;\n\n useEffect(() => {\n if (repository === null || meeting === null || meetingId === null) return undefined;\n let live = true;\n setLoading(true);\n setFailure(null);\n setRecord(null);\n // 🚨 TWO READERS, TWO DOORS, ONE BUNDLE (MRF-1).\n //\n // A signed-in member reads the record DIRECT from Supabase under RLS, as\n // they always have. A guest has no database at all — `anon` holds no grant\n // on the four org-scoped tables and widening it is forbidden (MRI-A10) — so\n // they read what the organization shares through `GET /v1/meet/record`,\n // authorized by the pass this device kept from the meeting. Both produce\n // the same `MeetingRecordBundle`, which is what keeps the two readers\n // looking at one product instead of two.\n const load =\n readerId === null && api !== null && tokens !== null && roomName !== null\n ? loadGuestMeetingRecord({\n api,\n repository,\n meetingId,\n meeting,\n roomToken: tokens.remembered(roomName),\n })\n : loadMeetingRecord(repository, meetingId, meeting, { userId: readerId });\n void load\n .then((bundle) => {\n if (!live) return;\n setRecordReaderId(readerId);\n setRecord(bundle);\n setLoading(false);\n })\n .catch((thrown: unknown) => {\n if (!live) return;\n // `loadMeetingRecord` converts every per-part refusal into a\n // restriction, so reaching here is a real failure and is stated as one.\n setFailure({\n message: (thrown as Error).message,\n remedy:\n (thrown as { remedy?: string }).remedy ??\n \"The meeting record could not be read. Reload the page; nothing was changed.\",\n });\n setLoading(false);\n });\n return () => {\n live = false;\n };\n }, [repository, meeting, meetingId, readerId, api, tokens, roomName, nonce]);\n\n return {\n loading: loading && failure === null,\n record: recordReaderId === readerId ? record : null,\n failure,\n asking,\n answer,\n coverage,\n askError,\n ask: useCallback(\n async (question: string) => {\n if (ai === null || meetingId === null) return;\n setAsking(true);\n setAskError(null);\n setAnswer(null);\n setCoverage(null);\n try {\n const result = await ai.ask({\n meetingId,\n question,\n onText: (text) => setAnswer(text),\n });\n setAnswer(result.text);\n setCoverage(result.coverage);\n } catch (thrown) {\n // A guest gets the server's own 403 here (\"a guest can read the notes\n // behind the link, but cannot ask the live assistant about a finished\n // meeting. Sign in to do that.\"). It is rendered verbatim.\n setAskError({\n message: (thrown as Error).message,\n remedy:\n (thrown as { remedy?: string }).remedy ??\n \"The assistant could not answer. Nothing was changed by the attempt.\",\n });\n } finally {\n setAsking(false);\n }\n },\n [ai, meetingId],\n ),\n reload: useCallback(() => setNonce((value) => value + 1), []),\n };\n}\n\n/**\n * EVERY MEETING THIS ORGANIZATION HAS, newest first — including the ended ones\n * (MRI-D2). A list that shows only live meetings is a list that empties itself\n * the moment the work is done, and it is what left every wrap-up unreachable.\n */\nexport interface UseMeetingsResult {\n readonly loading: boolean;\n readonly meetings: readonly MeetingRecord[];\n readonly hasMore: boolean;\n readonly failure: { readonly message: string; readonly remedy: string } | null;\n reload: () => void;\n}\n\nexport function useMeetings(limit = 25): UseMeetingsResult {\n const host = useMeetHost();\n const repository = host?.repository ?? null;\n const organizationId = host?.identity.organizationId ?? null;\n const [meetings, setMeetings] = useState<readonly MeetingRecord[]>([]);\n const [hasMore, setHasMore] = useState(false);\n const [loading, setLoading] = useState(true);\n const [failure, setFailure] = useState<{ message: string; remedy: string } | null>(null);\n const [nonce, setNonce] = useState(0);\n\n useEffect(() => {\n if (repository === null || organizationId === null) return undefined;\n let live = true;\n setLoading(true);\n setFailure(null);\n void repository\n .listMeetings({ organizationId, limit })\n .then((page) => {\n if (!live) return;\n setMeetings(page.items);\n setHasMore(page.hasMore);\n setLoading(false);\n })\n .catch((thrown: unknown) => {\n if (!live) return;\n setFailure({\n message: (thrown as Error).message,\n remedy:\n (thrown as { remedy?: string }).remedy ??\n \"The meetings could not be listed. Reload the page; nothing was changed.\",\n });\n setLoading(false);\n });\n return () => {\n live = false;\n };\n }, [repository, organizationId, limit, nonce]);\n\n return {\n loading: loading && failure === null,\n meetings,\n hasMore,\n failure,\n reload: useCallback(() => setNonce((value) => value + 1), []),\n };\n}\n\n\n/* ------------------------------------- what guests may read of this meeting */\n\n/**\n * THE HOST'S CHOICE FOR ONE MEETING (MRF-1).\n *\n * Arman ruled on 2026-09-12 that guest access to the post-meeting record is a\n * configuration and never a question: the system's default, the organization's\n * override, and this — a host deciding for the meeting in front of them,\n * because they are the only person who knows who was in the room and what was\n * said in it.\n *\n * `setting` is what the host chose (`default` means \"use my organization's\");\n * `effective` is what that resolves to RIGHT NOW, which is the only honest way\n * to render \"use my organization's setting\" — a label that does not say what\n * the organization's setting IS makes the host guess.\n *\n * The write is the SERVER's decision and it re-checks host power. This hook\n * never renders a control for a non-host; the component does that, and the\n * server refuses one anyway.\n */\nexport interface UseGuestRecordAccessResult {\n readonly setting: GuestRecordAccessSetting;\n /** Null until the server has said what `default` means for this meeting. */\n readonly effective: GuestRecordAccessResolution | null;\n readonly saving: boolean;\n readonly error: { readonly message: string; readonly remedy: string } | null;\n choose: (setting: GuestRecordAccessSetting) => Promise<void>;\n}\n\nexport function useGuestRecordAccess(\n meeting: MeetingRecord | null,\n): UseGuestRecordAccessResult {\n const host = useMeetHost();\n const api = host?.api ?? null;\n const stored = guestRecordAccessSetting(meeting);\n // The row's own value is the truth until a write of ours succeeds; this is\n // the optimistic half, and it is reset by the row arriving again.\n const [chosen, setChosen] = useState<GuestRecordAccessSetting | null>(null);\n const [effective, setEffective] = useState<GuestRecordAccessResolution | null>(null);\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<{ message: string; remedy: string } | null>(null);\n\n useEffect(() => {\n setChosen(null);\n }, [stored, meeting?.id]);\n\n return {\n setting: chosen ?? stored,\n effective,\n saving,\n error,\n choose: useCallback(\n async (next: GuestRecordAccessSetting) => {\n if (api === null || meeting === null) return;\n setSaving(true);\n setError(null);\n try {\n const result = await setGuestRecordAccess({\n api,\n meetingId: meeting.id,\n organizationId: meeting.organizationId,\n access: next,\n });\n setChosen(result.setting);\n setEffective(result.effective);\n } catch (thrown) {\n // The server's own sentence, rendered. A host who is not a host of\n // this meeting reads why, not a generic failure.\n setError({\n message: (thrown as Error).message,\n remedy:\n (thrown as { remedy?: string }).remedy ??\n \"Nothing was changed. Reload the page and try again.\",\n });\n } finally {\n setSaving(false);\n }\n },\n [api, meeting],\n ),\n };\n}\n","/**\n * THE STAGE — who is big, who is small, and who is not rendered at all.\n *\n * This is pure arithmetic on purpose: layout is the part of a meeting UI that\n * everyone re-derives inside a component and gets subtly wrong, and it is\n * trivially testable once it stops living in JSX.\n *\n * R5 SCALE HONESTY lives here. A 200-person meeting does not render 200 video\n * tiles — every browser dies, and LiveKit's adaptive stream cannot save a\n * layout that asked for 200 subscriptions. The grid PAGES, and the ordering is\n * deliberate rather than \"whatever the roster map iterated\":\n *\n * 1. a screen share (or an explicit pin) owns the stage;\n * 2. then the active speakers, most recent first;\n * 3. then anyone with a hand raised — they are asking to be seen;\n * 4. then cameras on before cameras off (an avatar tile is cheap);\n * 5. then stable by join time, so tiles do not shuffle every time someone\n * breathes. Shuffling tiles is the single most disorienting thing a\n * meeting UI can do.\n */\n\nimport type { MeetParticipant, ParticipantIdentity, StageLayout } from \"./types\";\n\nexport interface StageArgs {\n readonly participants: readonly MeetParticipant[];\n readonly layout: StageLayout;\n readonly pinned: ParticipantIdentity | null;\n readonly activeSpeakers: readonly ParticipantIdentity[];\n /**\n * The participant a HOST spotlighted for everyone (Meet wave 2). A local pin\n * outranks it on this screen; a screen share outranks both.\n */\n readonly spotlight?: ParticipantIdentity | null | undefined;\n /** How many tiles this viewport can honestly render. Default 12. */\n readonly pageSize?: number;\n readonly page?: number;\n}\n\nexport interface Stage {\n /** The large tile, when the layout has one. */\n readonly feature: MeetParticipant | null;\n /** What actually renders as a tile, already paged. */\n readonly tiles: readonly MeetParticipant[];\n /** Everyone not on this page. Rendered as \"+N others\", never dropped silently. */\n readonly overflow: number;\n readonly page: number;\n readonly pageCount: number;\n /** True when a screen share, not a person, is the reason for the big tile. */\n readonly presenting: boolean;\n}\n\nexport const DEFAULT_PAGE_SIZE = 12;\n\nexport function orderParticipants(\n participants: readonly MeetParticipant[],\n activeSpeakers: readonly ParticipantIdentity[],\n): readonly MeetParticipant[] {\n const speakerRank = new Map<ParticipantIdentity, number>();\n activeSpeakers.forEach((identity, index) => speakerRank.set(identity, index));\n\n return [...participants].sort((a, b) => {\n const speakerA = speakerRank.get(a.identity) ?? Number.MAX_SAFE_INTEGER;\n const speakerB = speakerRank.get(b.identity) ?? Number.MAX_SAFE_INTEGER;\n if (speakerA !== speakerB) return speakerA - speakerB;\n if (a.handRaised !== b.handRaised) return a.handRaised ? -1 : 1;\n if (a.cameraEnabled !== b.cameraEnabled) return a.cameraEnabled ? -1 : 1;\n // STABLE from here down. Join time, then identity — never Math.random,\n // never map order, both of which reshuffle the grid on every event.\n if (a.joinedAt !== b.joinedAt) return a.joinedAt < b.joinedAt ? -1 : 1;\n return a.identity < b.identity ? -1 : 1;\n });\n}\n\nexport function computeStage(args: StageArgs): Stage {\n const pageSize = Math.max(1, args.pageSize ?? DEFAULT_PAGE_SIZE);\n const ordered = orderParticipants(args.participants, args.activeSpeakers);\n\n const sharer = ordered.find((participant) => participant.screenSharing) ?? null;\n const pinnedParticipant =\n args.pinned === null\n ? null\n : ordered.find((participant) => participant.identity === args.pinned) ?? null;\n\n // A SCREEN SHARE OUTRANKS A PIN, deliberately: someone presenting is the\n // reason everyone is looking, and a stale pin hiding a live demo is the\n // complaint this rule exists to prevent.\n const spotlit =\n args.spotlight == null\n ? null\n : ordered.find((participant) => participant.identity === args.spotlight) ?? null;\n\n const feature =\n sharer !== null\n ? sharer\n : pinnedParticipant !== null && args.layout !== \"grid\"\n ? pinnedParticipant\n : spotlit !== null\n ? spotlit\n : args.layout === \"grid\"\n ? null\n : ordered[0] ?? null;\n\n const rest =\n feature === null\n ? ordered\n : ordered.filter((participant) => participant.identity !== feature.identity);\n\n const pageCount = Math.max(1, Math.ceil(rest.length / pageSize));\n const page = Math.min(Math.max(0, args.page ?? 0), pageCount - 1);\n const tiles = rest.slice(page * pageSize, page * pageSize + pageSize);\n\n return {\n feature,\n tiles,\n overflow: rest.length - tiles.length,\n page,\n pageCount,\n presenting: sharer !== null,\n };\n}\n\n/** Column count for a grid of N tiles — the shape that keeps tiles squarest. */\nexport function gridColumns(count: number): number {\n if (count <= 1) return 1;\n if (count <= 4) return 2;\n if (count <= 9) return 3;\n if (count <= 16) return 4;\n return 5;\n}\n","/**\n * THE MEETING RECORD — what a meeting IS once the room is gone (MRI-D2).\n *\n * 🚨 THE DEFECT THIS EXISTS TO KILL. Through 2026-09-08 a meeting produced a\n * wrap-up summary, decisions, owner-assigned action items, five windows of live\n * notes, thirty-two transcript segments and a recording — and then had NO\n * SURFACE AT ALL. `/meet/<slug>` fell back to `<PreJoin>` on an ended meeting,\n * so the durable link that R3 promises would outlive the meeting resolved to a\n * screen offering to join a room that no longer exists. Everything the campaign\n * built after the room closed was reachable only from SQL.\n *\n * Three rules hold this file together:\n *\n * 1. **Every read is INDEPENDENT and every refusal is NAMED.** The transcript,\n * the notes, the attendance list and the recording live in four RLS-guarded\n * tables, and a guest holding the link can read NONE of them (only\n * `meet_meeting_by_slug` is granted to `anon`). One `Promise.all` would turn\n * a permission boundary into a blank page. Known guest restrictions never issue private reads; each authenticated read that is refused\n * becomes a `MeetingRecordRestriction` with a sentence — the reader is told\n * what exists and why they cannot see it, which is the difference between a\n * record they can ask for and a product that looks broken.\n * 2. **A partial record is still a record.** A failed transcript read never\n * hides the summary somebody CAN read.\n * 3. **Nothing here computes meaning.** Grouping, ordering and formatting only.\n * The summary, decisions and action items are durable rows written by the\n * wrap-up mandate (D5/D18); this module never re-derives them from the\n * transcript, because two sources for one fact is how they start to disagree.\n */\n\nimport { formatDurationMs } from \"@ai-matrx/kit/format\";\nimport type { MeetApi } from \"./api\";\nimport { MeetError } from \"./errors\";\nimport { displayNameFor, learnNames, type NameBook } from \"./names\";\nimport type { MeetRepository } from \"./repository\";\nimport { MEET_ROUTES, ROOM_TOKEN_HEADER, type RoomToken } from \"./tokens\";\nimport type {\n MeetingAttendee,\n MeetingId,\n MeetingNote,\n MeetIdentity,\n MeetingRecord,\n OrganizationId,\n ParticipantIdentity,\n RecordingRecord,\n TranscriptSegment,\n} from \"./types\";\n\n/** One thing the reader could not see, and the honest reason. Never a blank. */\nexport interface MeetingRecordRestriction {\n /** Which part of the record: `transcript`, `notes`, `attendance`, `recording`. */\n readonly part: \"transcript\" | \"notes\" | \"attendance\" | \"recording\";\n readonly message: string;\n readonly remedy: string;\n}\n\n/** One visible access state, made from restrictions that share one remedy. */\nexport interface MeetingRecordRestrictionNotice {\n readonly parts: readonly MeetingRecordRestriction[\"part\"][];\n readonly message: string;\n readonly remedy: string;\n}\n\n/** A run of consecutive lines by one speaker — how a person reads a transcript. */\nexport interface TranscriptBlock {\n readonly id: string;\n /** Who spoke. Blocks break on THIS, never on the rendered name (MRI-A16). */\n readonly identity: ParticipantIdentity;\n readonly speaker: string;\n /** ISO of the first line in the block. */\n readonly startedAt: string;\n readonly lines: readonly TranscriptSegment[];\n}\n\nexport interface MeetingRecordBundle {\n readonly meeting: MeetingRecord;\n readonly attendees: readonly MeetingAttendee[];\n /** The wrap-up summary: `kind='note'` with `metadata.role='summary'` (D5). */\n readonly summary: MeetingNote | null;\n /** D20: the AUTHORITATIVE set — window rows the wrap-up superseded are out. */\n readonly decisions: readonly MeetingNote[];\n readonly actionItems: readonly MeetingNote[];\n /** The live-notes windows, in window order (D3). */\n readonly liveNotes: readonly MeetingNote[];\n readonly transcript: readonly TranscriptSegment[];\n /** The most recent recording attempt, whatever state it reached. */\n readonly recording: RecordingRecord | null;\n /** What this reader could NOT see. Rendered; never swallowed. */\n readonly restrictions: readonly MeetingRecordRestriction[];\n /**\n * Identity → name, learned from everything this read COULD see: the durable\n * attendance rows and the transcript's own `speaker` column. It is what stops\n * a raw LiveKit token reaching the screen when one of those reads was refused\n * (MRI-A16).\n */\n readonly names: NameBook;\n}\n\n/**\n * The current wrap-up summary. Repairs preserve the prior durable row for\n * history, then mark it `superseded_by`; every current-facing projection must\n * therefore make the same distinction as decisions and action items.\n */\nexport function activeWrapUpSummary(notes: readonly MeetingNote[]): MeetingNote | null {\n return notes.find((note) => note.role === \"summary\" && note.supersededBy === null) ?? null;\n}\n\n/**\n * The sentence a reader gets when the database refuses them a part of the\n * record. It is deliberately about TENANCY, not about them: `meet_notes`,\n * `meet_transcript_segments`, `meet_participants` and `meet_recordings` have no\n * `anon` policy at all, so a link-follower with no session reaches exactly the\n * meeting row and nothing else. That is the correct posture and it must be\n * SAID, not rendered as emptiness.\n */\nconst RESTRICTION_REMEDY =\n \"The people in this meeting's organization can read it. Sign in with an account in that \" +\n \"organization — following the link is enough to join a meeting, but not to read its record.\";\n\nconst PART_LABEL: Readonly<Record<MeetingRecordRestriction[\"part\"], string>> = {\n transcript: \"The transcript of this meeting is not readable from this account.\",\n notes: \"The notes, decisions and action items are not readable from this account.\",\n attendance: \"Who attended is not readable from this account.\",\n recording: \"The recording is not readable from this account.\",\n};\n\n/** A refusal is DATA. A transport wobble is not, and is re-thrown as itself. */\nfunction restrictionFor(\n part: MeetingRecordRestriction[\"part\"],\n error: unknown,\n): MeetingRecordRestriction {\n const code = (error as { code?: string }).code;\n const denied =\n code === \"forbidden\" || code === \"session-unavailable\" || code === \"not-found\";\n return {\n part,\n message: denied\n ? PART_LABEL[part]\n : `${PART_LABEL[part]} (${(error as Error).message ?? \"the read failed\"})`,\n remedy: denied\n ? RESTRICTION_REMEDY\n : (error as { remedy?: string }).remedy ??\n \"This is a transient read failure, not a permission decision. Reload the page.\",\n };\n}\n\n/**\n * Load the record parts the reader may request; state all restrictions.\n *\n * `meeting` is passed in when the caller already resolved it (the slug route\n * does, through the `anon`-granted RPC) — re-reading it through the table would\n * fail for exactly the reader who most needs the page to work.\n */\nexport async function loadMeetingRecord(\n repository: MeetRepository,\n meetingId: MeetingId,\n meeting: MeetingRecord,\n reader: Pick<MeetIdentity, \"userId\"> = { userId: null },\n): Promise<MeetingRecordBundle> {\n const restrictions: MeetingRecordRestriction[] = [];\n\n async function attempt<T>(\n part: MeetingRecordRestriction[\"part\"],\n run: () => Promise<T>,\n empty: T,\n ): Promise<T> {\n // No anonymous policy exists for these four tables. State the known\n // restriction without probing private data or generating expected 401s.\n if (reader.userId === null) {\n restrictions.push(restrictionFor(part, { code: \"session-unavailable\" }));\n return empty;\n }\n try {\n return await run();\n } catch (error) {\n restrictions.push(restrictionFor(part, error));\n return empty;\n }\n }\n\n // Four independent reads, four independent verdicts. Deliberately NOT\n // `Promise.all` over a single try/catch — see rule 1 in the header.\n const [attendees, notes, transcript, recordings] = await Promise.all([\n attempt<readonly MeetingAttendee[]>(\"attendance\", () => repository.attendees(meetingId), []),\n attempt<readonly MeetingNote[]>(\"notes\", () => repository.notes(meetingId), []),\n attempt<readonly TranscriptSegment[]>(\n \"transcript\",\n () => repository.transcript(meetingId),\n [],\n ),\n attempt<readonly RecordingRecord[]>(\n \"recording\",\n () => repository.recordings(meetingId),\n [],\n ),\n ]);\n\n return {\n meeting,\n attendees,\n summary: activeWrapUpSummary(notes),\n // 🚨 D20: THE WRAP-UP IS THE AUTHORITATIVE POST-MEETING SET. A window row the\n // wrap-up superseded is still in `notes` and still in the timeline below —\n // it is simply not listed a second time as a decision that was made.\n decisions: notes.filter((note) => note.kind === \"decision\" && note.supersededBy === null),\n actionItems: notes.filter(\n (note) => note.kind === \"action-item\" && note.supersededBy === null,\n ),\n liveNotes: notes\n .filter((note) => note.kind === \"note\" && note.role === null)\n // Window order, then creation order for the notes of one window.\n .slice()\n .sort((left, right) => {\n const a = left.window ?? Number.MAX_SAFE_INTEGER;\n const b = right.window ?? Number.MAX_SAFE_INTEGER;\n return a === b ? left.createdAt.localeCompare(right.createdAt) : a - b;\n }),\n transcript,\n // `recordings` is newest first; the record shows the latest attempt,\n // including a failed one — a recording that failed is a fact the reader\n // needs, not a row to hide.\n recording: recordings[0] ?? null,\n restrictions,\n names: learnNames(learnNames({}, attendees), transcript.map((line) => ({\n identity: line.identity,\n displayName: line.speaker,\n }))),\n };\n}\n\n/**\n * 🚨 **A READ THAT WAS REFUSED IS NOT AN EMPTY RESULT (MRI-A16).**\n *\n * On production 2026-09-09 a guest's record view said *\"No wrap-up was written\n * for this meeting\"* directly underneath a panel that had just told them, in\n * the same screen, that the notes are not readable from their account — and\n * *\"Nothing was recorded as a decision\"* beside a decision that exists\n * (MRI-C8). The page asserted an absence it had no way to know, which is worse\n * than saying nothing: a person who reads \"no wrap-up was written\" stops\n * looking for one.\n *\n * So no surface writes its own empty sentence any more. It asks here, and gets\n * either its absence sentence — earned, because the read SUCCEEDED and returned\n * nothing — or the refusal, said plainly.\n */\nexport const REFUSED_ABSENCE = \"This record is not shared with guests.\";\n\n/** Was this part of the record refused to this reader? */\nexport function wasRefused(\n bundle: MeetingRecordBundle,\n part: MeetingRecordRestriction[\"part\"],\n): boolean {\n return bundle.restrictions.some((restriction) => restriction.part === part);\n}\n\n/**\n * The sentence to show where a part of the record has nothing in it. NEVER an\n * absence claim over a read that was refused.\n */\nexport function absenceSentence(\n bundle: MeetingRecordBundle,\n part: MeetingRecordRestriction[\"part\"],\n absence: string,\n): string {\n return wasRefused(bundle, part) ? REFUSED_ABSENCE : absence;\n}\n\n/**\n * 🚨 **\"NO WRAP-UP WAS WRITTEN\" IS A CLAIM, AND FOR ~33 SECONDS IT WAS FALSE.**\n *\n * On production 2026-09-09 the HOST's record view said *\"No wrap-up was written\n * for this meeting\"* between 04:46:42 — the flip from the room to the record —\n * and 04:47:15, when the wrap-up landed. The read was permitted and genuinely\n * empty, so this is not the refusal class above; it is the OTHER way a screen\n * lies, by reading \"not here yet\" as \"never happened\". A person who reads *\"no\n * wrap-up was written\"* closes the tab.\n *\n * The meeting row already knows the difference, and it is not a guess: the\n * wrap-up is a durable job, `enqueue_wrap_up` stamps\n * `metadata.note_taker.intelligence.wrap_up` when it queues it, and the graph\n * action stamps `state: \"failed\"` when the pass refuses TERMINALLY. So:\n *\n * - a summary exists → `written`;\n * - the notes read was refused → `refused` (never an absence claim);\n * - the job is marked failed → `failed`, in the server's own words;\n * - the job is queued or running → `in-progress`, with a refresh affordance;\n * - nothing ever queued one → `absent`, which is the only EARNED absence.\n *\n * There is no timeout that flips `in-progress` into `absent`. A wrap-up that is\n * genuinely stuck says it is still being written — which is TRUE — rather than\n * inventing a verdict this browser has no way to reach.\n */\nexport type WrapUpStatus =\n | { readonly state: \"written\" }\n | { readonly state: \"in-progress\"; readonly message: string; readonly canRefresh: true }\n | { readonly state: \"failed\"; readonly message: string }\n | { readonly state: \"refused\"; readonly message: string }\n | { readonly state: \"absent\"; readonly message: string };\n\n/** What `metadata.note_taker` holds, as far as this file cares. */\nfunction noteTakerMetadata(meeting: MeetingRecord): Record<string, unknown> {\n const raw = (meeting.metadata as Record<string, unknown>)[\"note_taker\"];\n return typeof raw === \"object\" && raw !== null && !Array.isArray(raw)\n ? (raw as Record<string, unknown>)\n : {};\n}\n\nconst WRAP_UP_IN_PROGRESS =\n \"The wrap-up is being written… The summary, the decisions and the action items are \" +\n \"produced from the whole transcript once the meeting ends, which takes a moment longer \" +\n \"than the meeting does.\";\n\nconst WRAP_UP_ABSENT =\n \"No wrap-up was written for this meeting. A summary is produced from the transcript \" +\n \"when the meeting ends and the note-taker was in the room.\";\n\n/** Where the wrap-up actually is. Never \"absent\" over a job that is running. */\nexport function wrapUpStatus(bundle: MeetingRecordBundle): WrapUpStatus {\n if (bundle.summary !== null) return { state: \"written\" };\n if (wasRefused(bundle, \"notes\")) return { state: \"refused\", message: REFUSED_ABSENCE };\n\n const noteTaker = noteTakerMetadata(bundle.meeting);\n const intelligenceRaw = noteTaker[\"intelligence\"];\n const intelligence: Record<string, unknown> =\n typeof intelligenceRaw === \"object\" && intelligenceRaw !== null && !Array.isArray(intelligenceRaw)\n ? (intelligenceRaw as Record<string, unknown>)\n : {};\n const wrapUpRaw = intelligence[\"wrap_up\"];\n const wrapUp: Record<string, unknown> =\n typeof wrapUpRaw === \"object\" && wrapUpRaw !== null && !Array.isArray(wrapUpRaw)\n ? (wrapUpRaw as Record<string, unknown>)\n : {};\n\n if (wrapUp[\"state\"] === \"failed\") {\n const reason = wrapUp[\"reason\"];\n return {\n state: \"failed\",\n // THE SERVER'S OWN SENTENCE, verbatim. It already names the remedy, and a\n // house sentence over it would hide the one thing worth reading.\n message:\n typeof reason === \"string\" && reason.trim().length > 0\n ? reason.trim()\n : \"The wrap-up pass failed and no summary was written. It is not retried \" +\n \"automatically; a host can end the meeting again to re-queue it.\",\n };\n }\n\n const queued =\n typeof wrapUp[\"run_id\"] === \"string\" ||\n typeof intelligence[\"wrap_up_run_id\"] === \"string\" ||\n wrapUp[\"state\"] === \"queued\" ||\n wrapUp[\"state\"] === \"running\";\n // A meeting the note-taker actually attended will get a wrap-up even if this\n // browser loaded the record before the enqueue stamp landed — that race is\n // the whole defect, so `ended + the note-taker was there` is enough.\n const attended =\n noteTaker[\"state\"] === \"ended\" ||\n noteTaker[\"state\"] === \"transcribing\" ||\n noteTaker[\"state\"] === \"handoff_pending\";\n\n if (hasEnded(bundle.meeting) && (queued || attended)) {\n return { state: \"in-progress\", message: WRAP_UP_IN_PROGRESS, canRefresh: true };\n }\n return { state: \"absent\", message: WRAP_UP_ABSENT };\n}\n\n/**\n * GROUP THE TRANSCRIPT THE WAY A PERSON READS IT: consecutive lines by one\n * speaker become one block with one timestamp. Reading thirty-two rows each\n * re-stamped with a name and a clock is how a transcript becomes unreadable.\n */\nexport function groupTranscript(\n segments: readonly TranscriptSegment[],\n names: NameBook = {},\n): readonly TranscriptBlock[] {\n const blocks: TranscriptBlock[] = [];\n for (const segment of segments) {\n const last = blocks[blocks.length - 1];\n // 🚨 GROUPED BY IDENTITY, not by the rendered name (MRI-A16). Two people\n // whose names nobody ever learned both render \"Unnamed guest\", and merging\n // their lines into one block would put words in the wrong mouth — the exact\n // failure the honest placeholder exists to avoid.\n if (last !== undefined && last.identity === segment.identity) {\n blocks[blocks.length - 1] = { ...last, lines: [...last.lines, segment] };\n continue;\n }\n blocks.push({\n id: segment.id,\n identity: segment.identity,\n // One resolution, shared with the live rail — so the record and the room\n // can never disagree about who said something.\n speaker: displayNameFor(names, segment.identity, segment.speaker),\n startedAt: segment.startedAt,\n lines: [segment],\n });\n }\n return blocks;\n}\n\n/**\n * WHAT THE RECORDING IS DOING, in a sentence — including the two states people\n * hit most and understand least. `processing` is not \"broken\" and `failed` is\n * never silence: both say what happened and what to do.\n */\nexport function recordingNotice(recording: RecordingRecord | null): string | null {\n if (recording === null) return null;\n switch (recording.state) {\n case \"available\":\n if (recording.retention?.phase !== \"warning\") return null;\n return `This recording expires on ${retentionDueDate(recording.retention.dueAt)}. The transcript and notes remain available.`;\n case \"expired\":\n return \"This recording has expired. The transcript and notes remain available.\";\n case \"processing\":\n case \"stopping\":\n return \"The recording is still being processed. It appears here on its own once the file lands — nothing is lost while it is being written.\";\n case \"recording\":\n case \"starting\":\n return \"This recording is still being written. It becomes playable once the meeting's egress finishes.\";\n case \"failed\":\n return recording.failureReason !== null && recording.failureReason.length > 0\n ? `The recording failed: ${recording.failureReason}`\n : \"The recording failed and no file was produced. The transcript below was written separately and is unaffected.\";\n default:\n return null;\n }\n}\n\nfunction retentionDueDate(value: string): string {\n const dueAt = new Date(value);\n return Number.isNaN(dueAt.getTime()) ? \"its scheduled retention date\" : dueAt.toLocaleString();\n}\n\n/** Only an `available` recording has a file to play. Nothing else pretends to. */\nexport function playableRecordingFileId(recording: RecordingRecord | null): string | null {\n if (recording === null) return null;\n return recording.state === \"available\" ? recording.fileId : null;\n}\n\n/**\n * A MEETING IS OVER WHEN THE SERVER SAYS SO. `ended_at` is stamped by\n * `POST /v1/meet/end` or by the auto-end evaluation (MRI-A6) — never by a\n * client noticing the room is empty.\n */\nexport function hasEnded(meeting: MeetingRecord | null): boolean {\n return meeting !== null && meeting.endedAt !== null;\n}\n\n/**\n * \"Thursday, 8 September 2026, 4:21 PM · 19 minutes\". One shape everywhere.\n *\n * THE SPAN IS `formatDurationMs`'s (2026-09-12). This body used to divide by\n * `60_000` and pluralise \"minute\" itself — a duration formatter living in a\n * PACKAGE, found the day `aidream/apps/shared` became a scan root. `@ai-matrx/\n * meet` already depends on `@ai-matrx/kit`, and `style: \"long\"` is precisely\n * this voice (\"19 minutes\", \"1 minute\"). Three things improve by adopting it:\n * a 40-second meeting read \"0 minutes\" and now reads \"40 seconds\" (the\n * confident zero the package refuses), a 19-minute-35-second meeting read\n * \"20 minutes\" and now reads \"19 minutes\" (prose asserts at-least, so it\n * floors), and a 90-minute meeting reads \"1 hour\" instead of \"90 minutes\".\n */\nexport function meetingWhen(meeting: MeetingRecord, locale?: string): string {\n const start = meeting.startedAt ?? meeting.scheduledFor;\n if (start === null) return \"Time not recorded\";\n const startedAt = new Date(start);\n if (Number.isNaN(startedAt.getTime())) return \"Time not recorded\";\n const when = startedAt.toLocaleString(locale, {\n weekday: \"long\",\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n if (meeting.endedAt === null || meeting.startedAt === null) return when;\n const endedAt = new Date(meeting.endedAt);\n if (Number.isNaN(endedAt.getTime())) return when;\n const elapsedMs = endedAt.getTime() - startedAt.getTime();\n return `${when} · ${formatDurationMs(elapsedMs, { style: \"long\" })}`;\n}\n\n/* ═══════════════════════════════════════════════════════════════════════════\n * MRF-1 — WHAT A GUEST MAY READ, AND HOW THEY READ IT\n *\n * 🚨 THE DEFECT THIS CLOSES. Everything above this line is correct and was\n * still the wrong product: a guest who attended a meeting, was admitted by the\n * host, spoke, and was transcribed got FOUR refusal sentences where the record\n * should have been. `anon` has no grant on the four org-scoped tables and\n * widening it is forbidden (MRI-A10) — a meeting link is not organization\n * membership — so the honest refusals were the only thing this file could say.\n *\n * Arman ruled on 2026-09-12 that guest access to the record is a CONFIGURATION\n * and never a question: a system default, an organization override, and a\n * per-meeting setting a host chooses. The server resolves it and serves the\n * shared subset at `GET /api/v1/meet/record`, authorized by the room token this\n * device already holds. So this half does three things and no more:\n *\n * 1. reads that route and turns its answer into the SAME `MeetingRecordBundle`\n * the member lane produces — so one screen renders both readers and they can\n * never drift into two products;\n * 2. states every part the level does NOT share as a `MeetingRecordRestriction`\n * with the server's own sentence, which is what keeps \"not shared\" and\n * \"nothing happened\" different things on screen;\n * 3. gives a host the control that sets it.\n *\n * What it does NOT do is decide anything. The level, the refusals and the\n * remedies are the server's words; a client that computed its own would be a\n * second authority on who may read a transcript.\n * ═══════════════════════════════════════════════════════════════════════════ */\n\n\n/** How much of a finished meeting a GUEST may read. Pinned with the server. */\nexport type GuestRecordAccess = \"none\" | \"summary\" | \"full\";\n\n/** Widest last. The ORDER is the comparison, exactly as it is on the server. */\nexport const GUEST_RECORD_ACCESS_LEVELS: readonly GuestRecordAccess[] = [\n \"none\",\n \"summary\",\n \"full\",\n];\n\n/**\n * What a HOST may choose for one meeting. `default` is not a fourth level — it\n * is the absence of a per-meeting choice, and it is the only way to un-choose.\n */\nexport type GuestRecordAccessSetting = \"default\" | GuestRecordAccess;\n\nexport const GUEST_RECORD_ACCESS_CHOICES: readonly GuestRecordAccessSetting[] = [\n \"default\",\n \"summary\",\n \"full\",\n \"none\",\n];\n\n/** `meet_meetings.metadata.guest_record_access`. No DDL; a setting on a row. */\nexport const GUEST_RECORD_ACCESS_METADATA_KEY = \"guest_record_access\";\n\n/** What a host chose for THIS meeting, read from the row they already have. */\nexport function guestRecordAccessSetting(\n meeting: MeetingRecord | null,\n): GuestRecordAccessSetting {\n const raw = (meeting?.metadata as Record<string, unknown> | undefined)?.[\n GUEST_RECORD_ACCESS_METADATA_KEY\n ];\n return GUEST_RECORD_ACCESS_LEVELS.includes(raw as GuestRecordAccess)\n ? (raw as GuestRecordAccess)\n : \"default\";\n}\n\n/** The sentence on the host's control. Plain English, never a token. */\nexport function guestRecordAccessLabel(setting: GuestRecordAccessSetting): string {\n switch (setting) {\n case \"default\":\n return \"Use my organization's setting\";\n case \"summary\":\n return \"Summary, decisions and action items\";\n case \"full\":\n return \"Everything, including the transcript\";\n case \"none\":\n return \"Nothing — keep the record internal\";\n }\n}\n\n/** What each choice actually means for the people who were in the room. */\nexport function guestRecordAccessExplanation(setting: GuestRecordAccessSetting): string {\n switch (setting) {\n case \"default\":\n return \"Guests who attended read whatever your organization shares by default. An administrator sets that once, for every meeting nobody thinks about.\";\n case \"summary\":\n return \"Guests who attended read the wrap-up summary, the decisions, the action items, the notes taken as it happened, and who was here. They do not get the word-for-word transcript or the recording.\";\n case \"full\":\n return \"Guests who attended read everything this meeting produced, including the word-for-word transcript of what each person said.\";\n case \"none\":\n return \"Guests who attended are told plainly that this meeting's record is kept inside your organization. They see nothing of it.\";\n }\n}\n\n/** What came back from the server, so a surface never has to infer a level. */\nexport interface GuestRecordAccessResolution {\n readonly level: GuestRecordAccess;\n /** `meeting` when a host chose for this one; `organization` otherwise. */\n readonly source: \"meeting\" | \"organization\";\n}\n\n/** What the parts of the record the level does not share are called, and why. */\nconst NOT_SHARED: Readonly<Record<MeetingRecordRestriction[\"part\"], string>> = {\n transcript:\n \"The word-for-word transcript of this meeting is not shared with guests.\",\n notes: \"The notes, decisions and action items are not shared with guests.\",\n attendance: \"Who attended is not shared with guests.\",\n recording: \"The recording of this meeting is not shared with guests.\",\n};\n\nconst NOT_SHARED_REMEDY =\n \"The organization that held this meeting decided how much of its record guests can read. \" +\n \"If you need more, ask whoever invited you — they can send it to you, or change the \" +\n \"setting for this meeting.\";\n\nconst RESTRICTION_PART_NAME: Readonly<Record<MeetingRecordRestriction[\"part\"], string>> = {\n attendance: \"attendance\",\n notes: \"notes and decisions\",\n transcript: \"word-for-word transcript\",\n recording: \"recording\",\n};\n\nfunction joinPartNames(parts: readonly MeetingRecordRestriction[\"part\"][]): string {\n const names = parts.map((part) => RESTRICTION_PART_NAME[part]);\n if (names.length < 2) return names[0] ?? \"this part of the record\";\n if (names.length === 2) return `${names[0]} and ${names[1]}`;\n return `${names.slice(0, -1).join(\", \")}, and ${names[names.length - 1]}`;\n}\n\n/**\n * Repeated policy refusals are one access state, not four alarming cards.\n *\n * The individual rows remain durable data for absence handling in their own\n * sections. This projection groups only rows with the exact same remedy, so a\n * distinct transport or integrity failure remains visible on its own.\n */\nexport function summarizeMeetingRecordRestrictions(\n restrictions: readonly MeetingRecordRestriction[],\n): readonly MeetingRecordRestrictionNotice[] {\n const grouped = new Map<string, MeetingRecordRestriction[]>();\n for (const restriction of restrictions) {\n const rows = grouped.get(restriction.remedy) ?? [];\n rows.push(restriction);\n grouped.set(restriction.remedy, rows);\n }\n return [...grouped.values()].map((rows) => {\n if (rows.length === 1) {\n const row = rows[0]!;\n return { parts: [row.part], message: row.message, remedy: row.remedy };\n }\n return {\n parts: rows.map((row) => row.part),\n message: `Some parts of this meeting record are not available to this reader: ${joinPartNames(rows.map((row) => row.part))}.`,\n remedy: rows[0]!.remedy,\n };\n });\n}\n\n/**\n * Read the record the server shares with THIS guest.\n *\n * `roomToken` is the pass this device kept from the meeting\n * (`TokenClient.remembered`). It is presented in a header, never appended to\n * the URL. A guest with no pass, an expired pass, or a level of `none` gets the\n * server's refusal — as restrictions on a real bundle, so the screen says what\n * it cannot show instead of collapsing into an error page.\n */\nexport async function loadGuestMeetingRecord(args: {\n api: MeetApi;\n repository: MeetRepository;\n meetingId: MeetingId;\n meeting: MeetingRecord;\n roomToken: RoomToken | null;\n}): Promise<MeetingRecordBundle> {\n const { api, repository, meetingId, meeting, roomToken } = args;\n\n if (roomToken === null) {\n // NOT A GUESS AND NOT A FETCH. This browser has no pass for this meeting,\n // which the server would answer with the same sentence — asking it first\n // would only add a round trip and a 403 in the console.\n return refusedBundle(\n meeting,\n \"This meeting's record is only readable by the people who were in it.\",\n \"Open the meeting from the link you were invited with, in the same browser you used \" +\n \"to attend — that is what identifies you to this meeting. Signing in with an \" +\n \"account in the organization that held the meeting also works.\",\n );\n }\n\n let response: Response;\n try {\n response = await api.request({\n path: `${MEET_ROUTES.record}?meeting_id=${encodeURIComponent(meetingId)}`,\n method: \"GET\",\n // A GUEST HAS NO SESSION AND IS STILL A FIRST-CLASS READER (D6).\n requireAuth: false,\n operation: \"meet.record\",\n headers: { [ROOM_TOKEN_HEADER]: roomToken.token },\n });\n } catch (error) {\n // A transport wobble is not a permission decision and must not read as one.\n return refusedBundle(\n meeting,\n `This meeting's record could not be read (${(error as Error).message}).`,\n (error as { remedy?: string }).remedy ??\n \"This is a connection failure, not a decision about you. Reload the page.\",\n );\n }\n\n if (!response.ok) {\n const refusal = await readRefusal(response);\n return refusedBundle(meeting, refusal.message, refusal.remedy);\n }\n\n const body = (await response.json()) as Record<string, unknown>;\n const payload = (\n typeof body[\"data\"] === \"object\" && body[\"data\"] !== null ? body[\"data\"] : body\n ) as GuestRecordPayload;\n\n const rows = (key: keyof GuestRecordPayload): Record<string, unknown>[] =>\n Array.isArray(payload[key]) ? (payload[key] as Record<string, unknown>[]) : [];\n\n const attendees = rows(\"attendees\").map((row) => repository.projectAttendee(row));\n const notes = rows(\"notes\").map((row) => repository.projectNote(row));\n const transcript = rows(\"transcript\").map((row) => repository.projectSegment(row));\n const recordings = rows(\"recordings\").map((row) => repository.projectRecording(row));\n\n // 🚨 THE RESTRICTIONS COME FROM `shared`, NOT FROM AN EMPTY ARRAY. A level of\n // `summary` and a meeting where nobody spoke both produce zero transcript\n // rows, and telling the reader they are the same thing is the MRI-A16 defect.\n const shared = (payload.shared ?? {}) as Record<string, boolean>;\n const restrictions: MeetingRecordRestriction[] = [];\n for (const part of [\"attendance\", \"notes\", \"transcript\", \"recording\"] as const) {\n if (shared[part] === false) {\n restrictions.push({ part, message: NOT_SHARED[part], remedy: NOT_SHARED_REMEDY });\n }\n }\n\n return {\n meeting,\n attendees,\n summary: activeWrapUpSummary(notes),\n decisions: notes.filter((note) => note.kind === \"decision\" && note.supersededBy === null),\n actionItems: notes.filter(\n (note) => note.kind === \"action-item\" && note.supersededBy === null,\n ),\n liveNotes: notes\n .filter((note) => note.kind === \"note\" && note.role === null)\n .slice()\n .sort((left, right) => {\n const a = left.window ?? Number.MAX_SAFE_INTEGER;\n const b = right.window ?? Number.MAX_SAFE_INTEGER;\n return a === b ? left.createdAt.localeCompare(right.createdAt) : a - b;\n }),\n transcript,\n recording: recordings[0] ?? null,\n restrictions,\n names: learnNames(\n learnNames({}, attendees),\n transcript.map((line) => ({ identity: line.identity, displayName: line.speaker })),\n ),\n };\n}\n\n/** The row shapes the route returns — the same snake_case the tables use. */\ninterface GuestRecordPayload {\n readonly access?: GuestRecordAccess;\n readonly access_source?: \"meeting\" | \"organization\";\n readonly shared?: Record<string, boolean>;\n readonly attendees?: unknown;\n readonly notes?: unknown;\n readonly transcript?: unknown;\n readonly recordings?: unknown;\n readonly recording_notice?: string;\n}\n\n/**\n * THE SERVER'S OWN WORDS, verbatim. Every meet refusal carries\n * `{message, remedy}`, and a house sentence written over it would hide the one\n * thing worth reading — including the difference between \"your pass expired,\n * open the link again\" and \"this record is not shared with guests\".\n */\nasync function readRefusal(\n response: Response,\n): Promise<{ message: string; remedy: string }> {\n try {\n const body = (await response.json()) as Record<string, unknown>;\n const detail = (\n typeof body[\"detail\"] === \"object\" && body[\"detail\"] !== null ? body[\"detail\"] : body\n ) as Record<string, unknown>;\n const message = detail[\"message\"];\n const remedy = detail[\"remedy\"];\n if (typeof message === \"string\" && message.length > 0) {\n return {\n message,\n remedy:\n typeof remedy === \"string\" && remedy.length > 0\n ? remedy\n : \"Ask whoever hosted the meeting for what you need.\",\n };\n }\n } catch {\n /* falls through to the status sentence below */\n }\n return {\n message: `This meeting's record could not be read (the server answered ${response.status}).`,\n remedy:\n \"This is not a decision about you — it is a failure to reach the record. Reload the \" +\n \"page; if it repeats, tell whoever hosted the meeting.\",\n };\n}\n\n/** A real bundle whose every part is refused, with ONE reason said once. */\nfunction refusedBundle(\n meeting: MeetingRecord,\n message: string,\n remedy: string,\n): MeetingRecordBundle {\n return {\n meeting,\n attendees: [],\n summary: null,\n decisions: [],\n actionItems: [],\n liveNotes: [],\n transcript: [],\n recording: null,\n // Every empty collection below is a refusal, never evidence of absence.\n // The record renderer asks its own part before it writes an empty-state\n // sentence, so omitting attendance here made a denied roster read as\n // “Nobody attended.” `summarizeMeetingRecordRestrictions` still presents\n // this shared server reason once at the top of the record.\n restrictions: ([\"attendance\", \"notes\", \"transcript\", \"recording\"] as const).map(\n (part) => ({ part, message, remedy }),\n ),\n names: {},\n };\n}\n\n/**\n * A HOST chooses what guests may read of THIS meeting.\n *\n * Host power is the SERVER's decision and it re-checks it; this function exists\n * so the control has one call to make, and it returns what the choice RESOLVES\n * to so the screen never has to guess what \"my organization's setting\" means\n * today.\n */\nexport async function setGuestRecordAccess(args: {\n api: MeetApi;\n meetingId: MeetingId;\n organizationId: OrganizationId;\n access: GuestRecordAccessSetting;\n}): Promise<{\n readonly setting: GuestRecordAccessSetting;\n readonly effective: GuestRecordAccessResolution;\n}> {\n const response = await args.api.request({\n path: MEET_ROUTES.recordAccess,\n method: \"POST\",\n requireAuth: true,\n operation: \"meet.record.access\",\n body: {\n meeting_id: args.meetingId,\n organization_id: args.organizationId,\n access: args.access,\n },\n });\n if (!response.ok) {\n const refusal = await readRefusal(response);\n throw new MeetError(\"forbidden\", refusal.message, refusal.remedy);\n }\n const body = (await response.json()) as Record<string, unknown>;\n const payload = (\n typeof body[\"data\"] === \"object\" && body[\"data\"] !== null ? body[\"data\"] : body\n ) as {\n setting?: GuestRecordAccessSetting;\n effective?: GuestRecordAccessResolution;\n };\n return {\n setting: payload.setting ?? args.access,\n effective: payload.effective ?? { level: \"summary\", source: \"organization\" },\n };\n}\n\n/** What a guest is told when the level shares nothing. Rendered, never hidden. */\nexport const GUEST_RECORD_NOT_SHARED = NOT_SHARED;\n","\"use client\";\n\n/**\n * THE PRODUCT UI (R6/R7). Not a headless kernel with a note telling the host to\n * build the rest — the whole meeting surface ships here, because per THE\n * ALL-INCLUSIVE LAW a package that withholds its components withholds its\n * product.\n *\n * The bar: FaceTime and Zoom raised by Apple's design team. Concretely, and\n * every one of these is enforced by the stylesheet or the canary:\n *\n * - `dvh`, never `vh` — iOS Safari's `vh` includes the collapsing toolbar, so a\n * `100vh` stage puts the control bar under the browser chrome.\n * - Safe-area insets on the control bar, so the hang-up button is not under the\n * home indicator.\n * - 44px touch targets, and 16px input text (anything smaller zooms iOS Safari\n * on focus, which in a meeting looks like the app broke).\n * - Semantic tokens only. There is not one hardcoded color in the package.\n * - Real loading states and no dead ends: a control the actor cannot use is\n * ABSENT, never disabled-looking, and never a button that will be refused.\n */\n\nimport { useEffect, useLayoutEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport { ErrorBox } from \"@ai-matrx/design-system\";\nimport { avatarPaletteIndex, formatDurationMs, getInitials } from \"@ai-matrx/kit/format\";\nimport { fileDownloadPath, type MeetFileMedia } from \"../core/api\";\nimport { displayNameFor } from \"../core/names\";\nimport { uniqueAttendees } from \"../core/after\";\nimport { participantSummary } from \"../core/format\";\nimport { gridColumns } from \"../core/layout\";\nimport { meetingLink } from \"../core/meetings\";\nimport { asMeetingId } from \"../core/types\";\nimport type {\n CallInvite,\n CallMode,\n CallablePerson,\n MeetParticipant,\n MeetingKind,\n MeetingRecord,\n ParticipantIdentity,\n ParticipantRole,\n RoomName,\n} from \"../core/types\";\nimport {\n CameraIcon,\n CameraOffIcon,\n ChatIcon,\n CheckIcon,\n CloseIcon,\n HandIcon,\n LockIcon,\n MicIcon,\n MicOffIcon,\n PeopleIcon,\n PhoneIcon,\n PhoneOffIcon,\n PinIcon,\n RecordIcon,\n ScreenShareIcon,\n SettingsIcon,\n SignalIcon,\n SmileIcon,\n SpeakerIcon,\n SpotlightIcon,\n SparklesIcon,\n KeyboardIcon,\n FlagIcon,\n PencilIcon,\n MoreIcon,\n SearchIcon,\n WifiLowIcon,\n} from \"./icons\";\nimport {\n useCalls,\n useCanModerate,\n useConsentNotice,\n useElapsed,\n useEndMeeting,\n useHostControls,\n useLobby,\n useLocalMedia,\n useMeetAi,\n useGuestRecordAccess,\n useMeetingRecord,\n useMeetings,\n useRecording,\n useRoom,\n useStage,\n useTrack,\n useAudioLevel,\n useHandQueue,\n useMediaEffects,\n useModerationNotice,\n useMeetShortcuts,\n useReactions,\n MEET_SHORTCUTS,\n type UseHostControlsResult,\n} from \"./hooks\";\nimport {\n createCameraPreview,\n videoEffectsSupported,\n type CameraPreview,\n} from \"../core/livekit-driver\";\nimport type { VideoEffect } from \"../core/room-driver\";\nimport type { MediaEffects, RoomChatMessage } from \"../core/store\";\nimport { listenOnlyNotice } from \"../core/attendance\";\nimport {\n groupTranscript,\n guestRecordAccessExplanation,\n guestRecordAccessLabel,\n GUEST_RECORD_ACCESS_CHOICES,\n hasEnded,\n meetingWhen,\n playableRecordingFileId,\n recordingNotice,\n absenceSentence,\n REFUSED_ABSENCE,\n summarizeMeetingRecordRestrictions,\n wasRefused,\n wrapUpStatus,\n} from \"../core/record\";\nimport { isNoteTaker } from \"../core/note-taker\";\nimport {\n useDeviceSnapshot,\n useIsHost,\n useMeetHost,\n useMeetSnapshot,\n useRequiredMeetHost,\n useRole,\n type MeetHost,\n} from \"./provider\";\n\n/* ------------------------------------------------------------------ inert */\n\n/**\n * 🚨 A COMPONENT IN THIS FILE NEVER THROWS BECAUSE THE PROVIDER IS INERT.\n *\n * `<MeetProvider>` is deliberately inert until a Supabase client, an\n * organization and an identity are all real — which is every server render,\n * every signed-out visitor, and every moment before the active organization\n * hydrates. Through 0.2.0 the entry components called `useRequiredMeetHost()`\n * unconditionally, so the README's own three-line integration returned a 500 on\n * every route for those visitors, and the first real consumer had to guard OUR\n * components in ITS code (register MRI-D1, matrx-frontend 2026-09-08). That is\n * exactly the massage C22 forbids, and the defect was ours.\n *\n * The rule from 0.2.1 on: an entry component either renders its product or an\n * HONEST sentence — `<InertNotice>` below — and the ambient, always-mounted\n * ones (`<IncomingCallHost>`, `<CallButton>`, `<RecordingIndicator>`) render\n * NOTHING, because there is nothing truthful to say about a call surface on a\n * page with no runtime. Internal children (`<DevicePicker>`, `<HostMenu>`,\n * `<WaitingRoom>`) keep `useRequiredMeetHost()`: they are only ever rendered\n * BELOW one of these guards, so an absent host there is a package bug and must\n * be loud.\n */\nfunction InertNotice({ what }: { what: string }): ReactNode {\n return (\n <div className=\"mx-meet__empty\" role=\"status\">\n <p className=\"mx-meet__empty-title\">{what} is not ready yet</p>\n <p className=\"mx-meet__empty-body\">\n Calls and meetings need a signed-in identity and an active organization. This will\n appear as soon as they resolve.\n </p>\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ parts */\n\nexport function Avatar({\n name,\n url,\n size = 40,\n}: {\n name: string;\n url?: string | null;\n size?: number;\n}): ReactNode {\n const tint = avatarPaletteIndex(name);\n if (url != null && url.length > 0) {\n return (\n <img\n className=\"mx-meet__avatar\"\n src={url}\n alt=\"\"\n width={size}\n height={size}\n style={{ width: size, height: size }}\n />\n );\n }\n return (\n <span\n className=\"mx-meet__avatar mx-meet__avatar--initials\"\n style={{\n width: size,\n height: size,\n fontSize: Math.round(size * 0.38),\n background: `var(--mx-meet-avatar-${tint})`,\n }}\n aria-hidden=\"true\"\n >\n {getInitials(name)}\n </span>\n );\n}\n\nexport function ControlButton({\n label,\n active = false,\n danger = false,\n onClick,\n children,\n}: {\n label: string;\n active?: boolean;\n danger?: boolean;\n onClick: () => void;\n children: ReactNode;\n}): ReactNode {\n return (\n <button\n type=\"button\"\n className={[\n \"mx-meet__control\",\n active ? \"mx-meet__control--active\" : \"\",\n danger ? \"mx-meet__control--danger\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n // The accessible name is the STATE, not the icon: \"Unmute\" when muted.\n aria-label={label}\n title={label}\n onClick={onClick}\n >\n {children}\n </button>\n );\n}\n\n/**\n * The recording indicator. Rendered for EVERY participant, guests included —\n * there is no prop that hides it (R5). Consent is a property of the package.\n */\nexport function RecordingIndicator(): ReactNode {\n const { state, label } = useRecording();\n if (label === null) return null;\n return (\n <span\n className={`mx-meet__recording mx-meet__recording--${state}`}\n role=\"status\"\n aria-live=\"polite\"\n >\n <RecordIcon width={10} height={10} />\n {label}\n </span>\n );\n}\n\nexport function ConnectionDot({ quality }: { quality: string }): ReactNode {\n if (quality === \"excellent\" || quality === \"good\" || quality === \"unknown\") return null;\n // Only shown when it MEANS something. A permanent green dot teaches people\n // to ignore the indicator that matters.\n return (\n <span className={`mx-meet__quality mx-meet__quality--${quality}`} title={`Connection ${quality}`}>\n <WifiLowIcon width={14} height={14} />\n </span>\n );\n}\n\n/* ------------------------------------------------------------------- tile */\n\n/** Host, Co-host or Guest — and nothing at all for an ordinary participant. */\nfunction RoleBadge({ role }: { role: ParticipantRole }): ReactNode {\n if (role === \"host\") return <span className=\"mx-meet__badge\">Host</span>;\n if (role === \"cohost\") return <span className=\"mx-meet__badge\">Co-host</span>;\n if (role === \"guest\") return <span className=\"mx-meet__badge\">Guest</span>;\n return null;\n}\n\nexport function ParticipantTile({\n participant,\n featured = false,\n}: {\n participant: MeetParticipant;\n featured?: boolean;\n}): ReactNode {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const queue = useHandQueue();\n const [menu, setMenu] = useState(false);\n const videoRef = useTrack(\n participant.identity,\n participant.screenSharing ? \"screen\" : \"camera\",\n );\n const showVideo = participant.cameraEnabled || participant.screenSharing;\n const pinnedHere = snapshot?.pinned === participant.identity;\n const spotlit = snapshot?.spotlight === participant.identity;\n const handPosition = participant.handRaised\n ? queue.findIndex((entry) => entry.identity === participant.identity) + 1\n : 0;\n\n return (\n <div\n className={[\n \"mx-meet__tile\",\n featured ? \"mx-meet__tile--featured\" : \"\",\n participant.speaking ? \"mx-meet__tile--speaking\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n data-identity={participant.identity}\n >\n {showVideo ? (\n <video\n ref={videoRef}\n className=\"mx-meet__video\"\n autoPlay\n playsInline\n muted={participant.isLocal}\n />\n ) : (\n <div className=\"mx-meet__tile-placeholder\">\n <Avatar name={participant.displayName} url={participant.avatarUrl} size={featured ? 96 : 56} />\n </div>\n )}\n\n {participant.handRaised ? (\n <span className=\"mx-meet__tile-hand\" title={`Hand raised · ${ordinal(handPosition)} in line`}>\n <HandIcon width={14} height={14} />\n {handPosition > 0 ? handPosition : null}\n </span>\n ) : null}\n\n <div className=\"mx-meet__tile-bar\">\n <span className=\"mx-meet__tile-name\">\n {spotlit ? (\n <span title=\"Spotlighted for everyone\" className=\"mx-meet__tile-flag\">\n <SpotlightIcon width={12} height={12} />\n </span>\n ) : null}\n {participant.displayName}\n {participant.isLocal ? \" (you)\" : \"\"}\n {/* An agent is LABELLED. An invisible listener is the thing nobody\n should ever ship. */}\n {participant.isAgent ? <span className=\"mx-meet__badge\">AI</span> : null}\n {/* ONE role badge in this package (MRI-A11). */}\n <RoleBadge role={participant.role} />\n </span>\n {!participant.micEnabled ? <MicOffIcon width={14} height={14} /> : null}\n <QualityBars quality={participant.quality} />\n </div>\n\n <div className={menu ? \"mx-meet__tile-actions mx-meet__tile-actions--open\" : \"mx-meet__tile-actions\"}>\n <ControlButton\n label={pinnedHere ? \"Unpin\" : `Pin ${participant.displayName} for me`}\n active={pinnedHere}\n onClick={() => host?.engine.pin(pinnedHere ? null : participant.identity)}\n >\n <PinIcon width={16} height={16} />\n </ControlButton>\n <span className=\"mx-meet__anchor\">\n <ControlButton\n label={`More for ${participant.displayName}`}\n active={menu}\n onClick={() => setMenu(!menu)}\n >\n <MoreIcon width={16} height={16} />\n </ControlButton>\n {menu ? (\n <PersonMenu participant={participant} onClose={() => setMenu(false)} placement=\"down\" />\n ) : null}\n </span>\n </div>\n </div>\n );\n}\n\nfunction ordinal(position: number): string {\n if (position <= 0) return \"\";\n const suffix =\n position % 100 >= 11 && position % 100 <= 13\n ? \"th\"\n : ({ 1: \"st\", 2: \"nd\", 3: \"rd\" } as Record<number, string>)[position % 10] ?? \"th\";\n return `${position}${suffix}`;\n}\n\n/**\n * CONNECTION QUALITY, always legible (Meet wave 2). Four bars, like every phone:\n * a stable good connection is quiet (the bars are there, faint), and a poor or\n * lost one is loud. `unknown` draws nothing — a guess is not a reading.\n */\nexport function QualityBars({ quality }: { quality: string }): ReactNode {\n if (quality === \"unknown\") return null;\n const bars = quality === \"excellent\" ? 3 : quality === \"good\" ? 2 : quality === \"poor\" ? 1 : 0;\n const label =\n quality === \"lost\" ? \"Connection lost\" : quality === \"poor\" ? \"Poor connection\" : `Connection ${quality}`;\n return (\n <span className={`mx-meet__signal mx-meet__signal--${quality}`} title={label} aria-label={label} role=\"img\">\n <SignalIcon bars={bars as 0 | 1 | 2 | 3} width={14} height={14} />\n </span>\n );\n}\n\n/* ------------------------------------------------------------------ stage */\n\nexport function Stage({ pageSize }: { pageSize?: number }): ReactNode {\n const stage = useStage(pageSize);\n const columns = gridColumns(stage.tiles.length);\n\n if (stage.feature === null && stage.tiles.length === 0) {\n return (\n <div className=\"mx-meet__stage mx-meet__stage--empty\">\n <p className=\"mx-meet__empty-title\">Waiting for others to join</p>\n <p className=\"mx-meet__empty-body\">\n Share the meeting link and people can join from anywhere — no account needed.\n </p>\n </div>\n );\n }\n\n return (\n <div className={`mx-meet__stage${stage.feature !== null ? \" mx-meet__stage--speaker\" : \"\"}`}>\n {stage.feature !== null ? (\n <ParticipantTile participant={stage.feature} featured />\n ) : null}\n <div\n className=\"mx-meet__grid\"\n style={{ \"--mx-meet-columns\": columns } as React.CSSProperties}\n >\n {stage.tiles.map((participant) => (\n <ParticipantTile key={participant.identity} participant={participant} />\n ))}\n </div>\n {stage.overflow > 0 ? (\n <p className=\"mx-meet__overflow\">\n +{stage.overflow} more {stage.overflow === 1 ? \"person\" : \"people\"} in this meeting\n </p>\n ) : null}\n </div>\n );\n}\n\n/* ------------------------------------------------------------- control bar */\n\ntype Panel = \"none\" | \"chat\" | \"people\" | \"ai\" | \"settings\";\n\n/** Meet's own reaction set, in its order. */\nexport const MEET_REACTIONS: readonly string[] = [\"💖\", \"👍\", \"🎉\", \"👏\", \"😂\", \"😮\", \"😢\", \"🤔\", \"👎\"];\n\n/**\n * THE CONTROL BAR — one row, the same in the package's room and in any host\n * layout that composes it (the Board). Everything a person does in a meeting is\n * reachable from here or from the panels it opens, and every keyboard shortcut\n * is bound here, so a layout that renders this bar has all of it.\n */\nexport function ControlBar({ onLeave }: { onLeave?: () => void }): ReactNode {\n const room = useRoom();\n const recording = useRecording();\n const [panel, setPanel] = useState<Panel>(\"none\");\n const [chatTo, setChatTo] = useState<ParticipantIdentity | null>(null);\n const [popover, setPopover] = useState<\"none\" | \"reactions\" | \"more\">(\"none\");\n const [shortcuts, setShortcuts] = useState(false);\n const snapshot = useMeetSnapshot();\n const lobby = useLobby();\n const controls = useHostControls();\n const queue = useHandQueue();\n const micUnavailable = useLocalMedia().microphone.unavailable;\n const unread = useUnreadChat(panel === \"chat\");\n\n const toggle = (next: Panel) => setPanel(panel === next ? \"none\" : next);\n\n // A per-person menu anywhere in the layout asked to message someone privately.\n const privateChatAt = snapshot?.privateChatRequest?.at ?? null;\n const meetStore = useMeetHost()?.store ?? null;\n useEffect(() => {\n const request = meetStore?.snapshot().privateChatRequest ?? null;\n if (request === null) return;\n setChatTo(request.to);\n setPanel(\"chat\");\n meetStore?.patch({ privateChatRequest: null });\n }, [privateChatAt, meetStore]);\n\n useMeetShortcuts({\n mic: () => void room.toggleMicrophone(),\n camera: () => void room.toggleCamera(),\n hand: () => void room.toggleHand(),\n chat: () => toggle(\"chat\"),\n people: () => toggle(\"people\"),\n help: () => setShortcuts(true),\n });\n\n const hasSpotlight = snapshot?.spotlight !== null && snapshot?.spotlight !== undefined;\n\n return (\n <>\n <MeetingOverlays />\n {shortcuts ? <ShortcutsSheet onClose={() => setShortcuts(false)} /> : null}\n {panel === \"chat\" ? (\n <ChatPanel onClose={() => setPanel(\"none\")} to={chatTo} onTo={setChatTo} />\n ) : null}\n {panel === \"people\" ? (\n <PeoplePanel\n onClose={() => setPanel(\"none\")}\n onMessage={(identity) => {\n setChatTo(identity);\n setPanel(\"chat\");\n }}\n />\n ) : null}\n {panel === \"ai\" ? <AiPanel onClose={() => setPanel(\"none\")} /> : null}\n {panel === \"settings\" ? <SettingsPanel onClose={() => setPanel(\"none\")} /> : null}\n\n {/* The People panel says it inline, beside the row it acted on. */}\n {controls.notice !== null && panel !== \"people\" ? (\n <Toast text={controls.notice.text} failed={controls.notice.failed} onDone={controls.clearNotice} />\n ) : null}\n\n <div className=\"mx-meet__controls\">\n {/* The label states the REFUSAL when there is one, so the control is\n never a button that looks like it should work and doesn't. */}\n <ControlButton\n label={\n micUnavailable !== null\n ? `Unmute — ${micUnavailable.remedy}`\n : room.local?.micEnabled === true\n ? \"Mute (⌘D)\"\n : \"Unmute (⌘D)\"\n }\n active={room.local?.micEnabled === true}\n onClick={() => void room.toggleMicrophone()}\n >\n {room.local?.micEnabled === true ? <MicIcon /> : <MicOffIcon />}\n </ControlButton>\n\n <ControlButton\n label={room.local?.cameraEnabled === true ? \"Stop video (⌘E)\" : \"Start video (⌘E)\"}\n active={room.local?.cameraEnabled === true}\n onClick={() => void room.toggleCamera()}\n >\n {room.local?.cameraEnabled === true ? <CameraIcon /> : <CameraOffIcon />}\n </ControlButton>\n\n <ControlButton\n label={room.local?.screenSharing === true ? \"Stop sharing\" : \"Share screen\"}\n active={room.local?.screenSharing === true}\n onClick={() => void room.toggleScreenShare()}\n >\n <ScreenShareIcon />\n </ControlButton>\n\n <span className=\"mx-meet__anchor\">\n <ControlButton\n label=\"Send a reaction\"\n active={popover === \"reactions\"}\n onClick={() => setPopover(popover === \"reactions\" ? \"none\" : \"reactions\")}\n >\n <SmileIcon />\n </ControlButton>\n {popover === \"reactions\" ? (\n <Popover label=\"Reactions\" onClose={() => setPopover(\"none\")}>\n <div className=\"mx-meet__emoji-bar\">\n {MEET_REACTIONS.map((emoji) => (\n <button\n key={emoji}\n type=\"button\"\n className=\"mx-meet__emoji\"\n aria-label={`React ${emoji}`}\n onClick={() => void room.react(emoji)}\n >\n {emoji}\n </button>\n ))}\n </div>\n </Popover>\n ) : null}\n </span>\n\n <ControlButton\n label={room.local?.handRaised === true ? \"Lower hand (⌘⌥H)\" : \"Raise hand (⌘⌥H)\"}\n active={room.local?.handRaised === true}\n onClick={() => void room.toggleHand()}\n >\n <HandIcon />\n </ControlButton>\n\n <ControlButton label=\"Chat (⌘⌥C)\" active={panel === \"chat\"} onClick={() => toggle(\"chat\")}>\n <ChatIcon />\n {unread > 0 ? <span className=\"mx-meet__dot\" aria-hidden=\"true\" /> : null}\n </ControlButton>\n\n <ControlButton\n label={\n lobby.waiting.length > 0\n ? `People — ${lobby.waiting.length} waiting`\n : `People — ${(snapshot?.participants ?? []).length} in the meeting`\n }\n active={panel === \"people\"}\n onClick={() => toggle(\"people\")}\n >\n <PeopleIcon />\n {lobby.waiting.length > 0 || (controls.isHost && queue.length > 0) ? (\n <span className=\"mx-meet__dot\" aria-hidden=\"true\" />\n ) : null}\n </ControlButton>\n\n {/* The AI control appears only when the meeting's AI is on — never a\n button that resolves to \"not configured\". */}\n <AiControl active={panel === \"ai\"} onToggle={() => toggle(\"ai\")} />\n\n {recording.canStart ? (\n <ControlButton label=\"Start recording\" onClick={() => void recording.start()}>\n <RecordIcon />\n </ControlButton>\n ) : null}\n {recording.canStop ? (\n <ControlButton label=\"Stop recording\" active onClick={() => void recording.stop()}>\n <RecordIcon />\n </ControlButton>\n ) : null}\n\n <span className=\"mx-meet__anchor\">\n <ControlButton\n label=\"More options\"\n active={popover === \"more\" || panel === \"settings\"}\n onClick={() => setPopover(popover === \"more\" ? \"none\" : \"more\")}\n >\n <MoreIcon />\n </ControlButton>\n {popover === \"more\" ? (\n <Popover label=\"More options\" onClose={() => setPopover(\"none\")}>\n <div className=\"mx-meet__menu\" role=\"menu\">\n <MenuItem\n onSelect={() => {\n setPopover(\"none\");\n setPanel(\"settings\");\n }}\n >\n <SettingsIcon width={16} height={16} /> Audio, video and effects\n </MenuItem>\n <MenuItem\n onSelect={() => {\n setPopover(\"none\");\n setShortcuts(true);\n }}\n >\n <KeyboardIcon width={16} height={16} /> Keyboard shortcuts\n </MenuItem>\n {controls.isHost ? (\n <>\n <div className=\"mx-meet__menu-sep\" role=\"separator\" />\n <MenuItem\n onSelect={() => {\n setPopover(\"none\");\n void controls.run({ action: \"mute_all\" });\n }}\n >\n <MicOffIcon width={16} height={16} /> Mute everyone\n </MenuItem>\n <MenuItem\n onSelect={() => {\n setPopover(\"none\");\n void controls.run({ action: \"ask_all_unmute\" });\n }}\n >\n <MicIcon width={16} height={16} /> Ask everyone to unmute\n </MenuItem>\n {queue.length > 0 ? (\n <MenuItem\n onSelect={() => {\n setPopover(\"none\");\n void controls.run({ action: \"lower_all_hands\" });\n }}\n >\n <HandIcon width={16} height={16} /> Lower all hands ({queue.length})\n </MenuItem>\n ) : null}\n {hasSpotlight ? (\n <MenuItem\n onSelect={() => {\n setPopover(\"none\");\n void controls.run({ action: \"spotlight\", identity: null });\n }}\n >\n <SpotlightIcon width={16} height={16} /> Remove spotlight\n </MenuItem>\n ) : null}\n </>\n ) : null}\n </div>\n </Popover>\n ) : null}\n </span>\n\n <ControlButton\n label=\"Leave\"\n danger\n onClick={() => {\n void room.leave();\n onLeave?.();\n }}\n >\n <PhoneOffIcon />\n </ControlButton>\n </div>\n </>\n );\n}\n\n/** Messages that arrived while the chat panel was closed. */\nfunction useUnreadChat(open: boolean): number {\n const snapshot = useMeetSnapshot();\n const chat = snapshot?.chat ?? [];\n const local = snapshot?.localIdentity ?? null;\n const [seen, setSeen] = useState(0);\n useEffect(() => {\n if (open) setSeen(chat.length);\n }, [open, chat.length]);\n // The saved history read on join is not \"unread\" — only what arrives after it.\n const loaded = snapshot?.chatLoaded === true;\n const [baseline, setBaseline] = useState<number | null>(null);\n useEffect(() => {\n if (loaded && baseline === null) setBaseline(chat.length);\n }, [loaded, baseline, chat.length]);\n if (open) return 0;\n const from = Math.max(seen, baseline ?? chat.length);\n return chat.slice(from).filter((message) => message.identity !== local).length;\n}\n\n/**\n * A small floating surface anchored to its control. Escape and an outside click\n * close it. It is FIXED-positioned from the anchor's rectangle, because the\n * controls it hangs off live inside tiles that clip (`overflow: hidden`) and\n * inside a Board that pans — an absolutely positioned menu would be cut in half.\n */\nfunction Popover({\n label,\n onClose,\n children,\n placement = \"up\",\n}: {\n label: string;\n onClose: () => void;\n children: ReactNode;\n placement?: \"up\" | \"down\";\n}): ReactNode {\n const ref = useRef<HTMLDivElement | null>(null);\n // FIXED FROM THE FIRST FRAME. Hidden but in normal flow, the popover made its\n // anchor as tall as the whole menu, so the anchor's measured bottom was the\n // menu's bottom and the menu opened a full menu-height below its button\n // (host menu: Make host / Report / Remove off-screen, 2026-09-27).\n const [style, setStyle] = useState<React.CSSProperties>({\n position: \"fixed\",\n top: 0,\n left: 0,\n visibility: \"hidden\",\n });\n useLayoutEffect(() => {\n const element = ref.current;\n const anchor = element?.parentElement ?? null;\n if (element === null || anchor === null) return;\n const place = () => {\n const rect = anchor.getBoundingClientRect();\n const width = element.offsetWidth;\n const height = element.offsetHeight;\n const gutter = 8;\n const left = Math.min(\n Math.max(gutter, rect.left + rect.width / 2 - width / 2),\n window.innerWidth - width - gutter,\n );\n const fitsBelow = rect.bottom + gutter + height <= window.innerHeight;\n const fitsAbove = rect.top - gutter - height >= 0;\n if (!fitsBelow && !fitsAbove) {\n // NEITHER SIDE HOLDS IT (a tall host menu from a row mid-screen): pin it\n // inside the viewport and let it scroll, so the last items — Make host,\n // Remove from meeting — are never below the fold (2026-09-27).\n const top = Math.max(gutter, window.innerHeight - height - gutter);\n setStyle({\n position: \"fixed\",\n left,\n top,\n maxHeight: window.innerHeight - top - gutter,\n overflowY: \"auto\",\n });\n return;\n }\n const down = placement === \"down\" ? fitsBelow || !fitsAbove : !fitsAbove && fitsBelow;\n setStyle(\n down\n ? { position: \"fixed\", left, top: rect.bottom + gutter }\n : { position: \"fixed\", left, bottom: window.innerHeight - rect.top + gutter },\n );\n };\n place();\n // Re-placed when the layout moves (a lobby row arriving, a panel scrolling),\n // not only on window resize.\n const frame = requestAnimationFrame(place);\n const observer =\n typeof ResizeObserver === \"undefined\" ? null : new ResizeObserver(() => place());\n observer?.observe(document.body);\n observer?.observe(element);\n window.addEventListener(\"resize\", place);\n window.addEventListener(\"scroll\", place, true);\n return () => {\n cancelAnimationFrame(frame);\n observer?.disconnect();\n window.removeEventListener(\"resize\", place);\n window.removeEventListener(\"scroll\", place, true);\n };\n }, [placement]);\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n const onPointer = (event: PointerEvent) => {\n const anchor = ref.current?.parentElement ?? null;\n if (anchor !== null && !anchor.contains(event.target as Node)) onClose();\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"pointerdown\", onPointer);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"pointerdown\", onPointer);\n };\n }, [onClose]);\n return (\n <div ref={ref} className=\"mx-meet__popover\" style={style} role=\"dialog\" aria-label={label}>\n {children}\n </div>\n );\n}\n\nfunction MenuItem({\n onSelect,\n danger = false,\n children,\n}: {\n onSelect: () => void;\n danger?: boolean;\n children: ReactNode;\n}): ReactNode {\n return (\n <button\n type=\"button\"\n role=\"menuitem\"\n className={danger ? \"mx-meet__menu-item mx-meet__menu-item--danger\" : \"mx-meet__menu-item\"}\n onClick={onSelect}\n >\n {children}\n </button>\n );\n}\n\n/** A transient sentence above the control bar. Stays 4 s, or until dismissed. */\nfunction Toast({ text, failed, onDone }: { text: string; failed: boolean; onDone: () => void }): ReactNode {\n useEffect(() => {\n const timer = setTimeout(onDone, failed ? 7000 : 4000);\n return () => clearTimeout(timer);\n }, [text, failed, onDone]);\n return (\n <div className={failed ? \"mx-meet__toast mx-meet__toast--failed\" : \"mx-meet__toast\"} role=\"status\">\n <span>{text}</span>\n <button type=\"button\" className=\"mx-meet__toast-close\" aria-label=\"Dismiss\" onClick={onDone}>\n <CloseIcon width={14} height={14} />\n </button>\n </div>\n );\n}\n\n/**\n * WHAT FLOATS OVER THE MEETING, in every layout (Meet wave 2): the reactions\n * everyone sends, and what a host just did to THIS person — \"the host is asking\n * you to unmute\" with the Unmute button right there, which is the whole point.\n */\nexport function MeetingOverlays(): ReactNode {\n const reactions = useReactions();\n const { notice, dismiss } = useModerationNotice();\n const room = useRoom();\n return (\n <>\n <ReactionOverlay reactions={reactions} />\n {notice !== null && notice.kind !== \"removed\" ? (\n // A host's request (\"the host is asking you to unmute\"), not an error:\n // an assertive status, so it is announced at once without being filed\n // as a failure (design-system error-box census).\n <div className=\"mx-meet__notice-bar\" role=\"status\" aria-live=\"assertive\">\n <span>{notice.text}</span>\n {notice.kind === \"ask-unmute\" && room.local?.micEnabled !== true ? (\n <button\n type=\"button\"\n className=\"mx-meet__primary mx-meet__primary--small\"\n onClick={() => {\n dismiss();\n void room.toggleMicrophone();\n }}\n >\n Unmute\n </button>\n ) : null}\n <button type=\"button\" className=\"mx-meet__toast-close\" aria-label=\"Dismiss\" onClick={dismiss}>\n <CloseIcon width={14} height={14} />\n </button>\n </div>\n ) : null}\n </>\n );\n}\n\n/** Every shortcut, on one sheet. Opened by Shift+? or from More options. */\nexport function ShortcutsSheet({ onClose }: { onClose: () => void }): ReactNode {\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [onClose]);\n return (\n <div className=\"mx-meet__sheet-backdrop\" onClick={onClose}>\n <div\n className=\"mx-meet__sheet\"\n role=\"dialog\"\n aria-label=\"Keyboard shortcuts\"\n onClick={(event) => event.stopPropagation()}\n >\n <header className=\"mx-meet__panel-head\">\n <h2 className=\"mx-meet__panel-title\">Keyboard shortcuts</h2>\n <ControlButton label=\"Close\" onClick={onClose}>\n <CloseIcon width={16} height={16} />\n </ControlButton>\n </header>\n <dl className=\"mx-meet__shortcuts\">\n {MEET_SHORTCUTS.map((shortcut) => (\n <div key={shortcut.id} className=\"mx-meet__shortcut\">\n <dt>{shortcut.label}</dt>\n <dd>\n <kbd className=\"mx-meet__kbd\">{shortcut.keys}</kbd>\n </dd>\n </div>\n ))}\n </dl>\n </div>\n </div>\n );\n}\n\n/**\n * The assistant control. It appears for every meeting whose AI is on, because\n * as of 0.3.0 the capability is the SERVER's: there is no host config that\n * could leave it unfilled, and a meeting with no Holder bound gets the server's\n * sentence in the panel rather than a control that never appears. A meeting\n * with `ai_enabled = false` gets NO control at all — absent, not disabled.\n */\nfunction AiControl({ active, onToggle }: { active: boolean; onToggle: () => void }): ReactNode {\n const snapshot = useMeetSnapshot();\n const meeting = snapshot?.meeting ?? null;\n if (meeting === null || !meeting.aiEnabled) return null;\n return (\n <ControlButton label=\"Meeting assistant\" active={active} onClick={onToggle}>\n <SparklesIcon />\n </ControlButton>\n );\n}\n\n/* ----------------------------------------------------------------- panels */\n\nfunction PanelShell({\n title,\n onClose,\n children,\n}: {\n title: string;\n onClose: () => void;\n children: ReactNode;\n}): ReactNode {\n return (\n <aside className=\"mx-meet__panel\" aria-label={title}>\n <header className=\"mx-meet__panel-head\">\n <h2 className=\"mx-meet__panel-title\">{title}</h2>\n <ControlButton label=\"Close panel\" onClick={onClose}>\n <CloseIcon width={16} height={16} />\n </ControlButton>\n </header>\n <div className=\"mx-meet__panel-body\">{children}</div>\n </aside>\n );\n}\n\n/**\n * IN-MEETING CHAT (Meet wave 2). A message to everyone is SAVED with the\n * meeting — a late joiner scrolls up and reads it, and it is part of the record.\n * A private message goes to one person only and is never saved; the composer\n * says which of the two you are about to send.\n */\nexport function ChatPanel({\n onClose,\n to = null,\n onTo,\n}: {\n onClose: () => void;\n to?: ParticipantIdentity | null;\n onTo?: (identity: ParticipantIdentity | null) => void;\n}): ReactNode {\n const snapshot = useMeetSnapshot();\n const room = useRoom();\n const [draft, setDraft] = useState(\"\");\n const [recipient, setRecipient] = useState<ParticipantIdentity | null>(to);\n const listRef = useRef<HTMLUListElement | null>(null);\n const messages = snapshot?.chat ?? [];\n const local = snapshot?.localIdentity ?? null;\n const people = (snapshot?.participants ?? []).filter(\n (participant) => !participant.isLocal && !participant.isAgent,\n );\n const recipientName =\n recipient === null ? null : people.find((p) => p.identity === recipient)?.displayName ?? null;\n\n useEffect(() => setRecipient(to), [to]);\n useEffect(() => {\n const list = listRef.current;\n if (list !== null) list.scrollTop = list.scrollHeight;\n }, [messages.length]);\n\n const choose = (next: ParticipantIdentity | null) => {\n setRecipient(next);\n onTo?.(next);\n };\n\n return (\n <PanelShell title=\"Chat\" onClose={onClose}>\n <ul className=\"mx-meet__chat\" ref={listRef}>\n {snapshot?.chatHistoryError != null ? (\n <li className=\"mx-meet__panel-note\">{snapshot.chatHistoryError}</li>\n ) : null}\n {snapshot?.chatLoaded !== true && messages.length === 0 ? (\n <li className=\"mx-meet__panel-note\">Reading earlier messages…</li>\n ) : messages.length === 0 && snapshot?.chatHistoryError == null ? (\n <li className=\"mx-meet__panel-note\">\n No messages yet. Messages to everyone stay with the meeting, so people who join later\n see them.\n </li>\n ) : null}\n {messages.map((message) => (\n <ChatLine key={message.id} message={message} local={local} people={people} />\n ))}\n </ul>\n <form\n className=\"mx-meet__composer mx-meet__composer--chat\"\n onSubmit={(event) => {\n event.preventDefault();\n const text = draft;\n if (text.trim().length === 0) return;\n setDraft(\"\");\n if (recipient === null) void room.sendChat(text).catch(() => undefined);\n else void room.sendPrivateChat(recipient, text);\n }}\n >\n {people.length > 0 ? (\n <select\n className=\"mx-meet__select mx-meet__select--compact\"\n aria-label=\"Send to\"\n value={recipient ?? \"\"}\n onChange={(event) =>\n choose(event.target.value === \"\" ? null : (event.target.value as ParticipantIdentity))\n }\n >\n <option value=\"\">Everyone</option>\n {people.map((participant) => (\n <option key={participant.identity} value={participant.identity}>\n {participant.displayName} (private)\n </option>\n ))}\n </select>\n ) : null}\n <div className=\"mx-meet__composer-row\">\n <input\n className=\"mx-meet__input\"\n value={draft}\n onChange={(event) => setDraft(event.target.value)}\n placeholder={recipientName === null ? \"Message everyone\" : `Message ${recipientName} privately`}\n aria-label={recipientName === null ? \"Message everyone\" : `Message ${recipientName} privately`}\n maxLength={4000}\n />\n <button type=\"submit\" className=\"mx-meet__send\" disabled={draft.trim().length === 0}>\n Send\n </button>\n </div>\n {recipientName !== null ? (\n <p className=\"mx-meet__panel-note\">Only {recipientName} sees this. Private messages are not saved.</p>\n ) : null}\n </form>\n </PanelShell>\n );\n}\n\nfunction ChatLine({\n message,\n local,\n people,\n}: {\n message: RoomChatMessage;\n local: ParticipantIdentity | null;\n people: readonly MeetParticipant[];\n}): ReactNode {\n const mine = message.identity === local;\n const privateTo = message.to ?? null;\n const counterpart =\n privateTo === null\n ? null\n : mine\n ? people.find((p) => p.identity === privateTo)?.displayName ?? \"them\"\n : \"you\";\n return (\n <li\n className={[\n \"mx-meet__chat-line\",\n privateTo !== null ? \"mx-meet__chat-line--private\" : \"\",\n message.failed !== undefined ? \"mx-meet__chat-line--failed\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n <span className=\"mx-meet__chat-meta\">\n <strong>{mine ? \"You\" : message.displayName}</strong>\n {counterpart !== null ? <span className=\"mx-meet__chat-private\">to {counterpart} · private</span> : null}\n <time dateTime={message.at}>{clockOf(message.at)}</time>\n </span>\n <span className=\"mx-meet__chat-text\">{message.text}</span>\n {message.failed !== undefined ? (\n <span className=\"mx-meet__chat-failed\">{message.failed}</span>\n ) : privateTo === null && message.saved === false ? (\n <span className=\"mx-meet__chat-pending\">\n {message.id.startsWith(\"pending-\") ? \"Sending…\" : \"Not saved — people who join later will not see this\"}\n </span>\n ) : null}\n </li>\n );\n}\n\nexport function PeoplePanel({\n onClose,\n onMessage,\n}: {\n onClose: () => void;\n onMessage?: (identity: ParticipantIdentity) => void;\n}): ReactNode {\n const snapshot = useMeetSnapshot();\n const controls = useHostControls();\n const queue = useHandQueue();\n const [query, setQuery] = useState(\"\");\n const [menuFor, setMenuFor] = useState<ParticipantIdentity | null>(null);\n // THE LOCAL ROW IS BADGED FROM THE EFFECTIVE ROLE (MRI-A11).\n const myRole = useRole();\n const local = snapshot?.localIdentity ?? null;\n const everyone = snapshot?.participants ?? [];\n const needle = query.trim().toLowerCase();\n const shown =\n needle.length === 0\n ? everyone\n : everyone.filter((participant) => participant.displayName.toLowerCase().includes(needle));\n\n return (\n <PanelShell title={`People (${everyone.length})`} onClose={onClose}>\n <LobbyPanel />\n\n {queue.length > 0 ? (\n <section className=\"mx-meet__section\" aria-label=\"Raised hands\">\n <header className=\"mx-meet__section-head\">\n <h3 className=\"mx-meet__section-title\">Raised hands · {queue.length}</h3>\n {controls.isHost ? (\n <button\n type=\"button\"\n className=\"mx-meet__link\"\n onClick={() => void controls.run({ action: \"lower_all_hands\" })}\n >\n Lower all\n </button>\n ) : null}\n </header>\n <ol className=\"mx-meet__queue\">\n {queue.map((participant) => (\n <li key={participant.identity} className=\"mx-meet__person\">\n <Avatar name={participant.displayName} url={participant.avatarUrl} size={28} />\n <span className=\"mx-meet__person-name\">\n {participant.displayName}\n {participant.identity === local ? <span className=\"mx-meet__you\"> (you)</span> : null}\n </span>\n {controls.isHost || participant.identity === local ? (\n <button\n type=\"button\"\n className=\"mx-meet__link\"\n onClick={() =>\n void controls.run({ action: \"lower_hand\", identity: participant.identity })\n }\n >\n Lower\n </button>\n ) : null}\n </li>\n ))}\n </ol>\n </section>\n ) : null}\n\n {controls.isHost && everyone.length > 1 ? (\n <div className=\"mx-meet__bulk\">\n <button type=\"button\" className=\"mx-meet__chip\" onClick={() => void controls.run({ action: \"mute_all\" })}>\n <MicOffIcon width={14} height={14} /> Mute all\n </button>\n <button\n type=\"button\"\n className=\"mx-meet__chip\"\n onClick={() => void controls.run({ action: \"ask_all_unmute\" })}\n >\n <MicIcon width={14} height={14} /> Ask all to unmute\n </button>\n </div>\n ) : null}\n\n {everyone.length > 4 ? (\n <label className=\"mx-meet__search\">\n <SearchIcon width={16} height={16} />\n <input\n className=\"mx-meet__input mx-meet__input--bare\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder=\"Search people\"\n aria-label=\"Search people\"\n />\n </label>\n ) : null}\n\n {controls.notice !== null ? (\n <p className={controls.notice.failed ? \"mx-meet__error\" : \"mx-meet__notice\"} role=\"status\">\n {controls.notice.text}\n </p>\n ) : null}\n\n <ul className=\"mx-meet__people\">\n {shown.map((participant) => (\n <li key={participant.identity} className=\"mx-meet__person\">\n <Avatar name={participant.displayName} url={participant.avatarUrl} size={32} />\n <span className=\"mx-meet__person-name\">\n {participant.displayName}\n {participant.identity === local ? <span className=\"mx-meet__you\"> (you)</span> : null}\n <RoleBadge role={participant.identity === local ? myRole : participant.role} />\n {isNoteTaker(participant) ? (\n <span className=\"mx-meet__badge\">Meeting assistant</span>\n ) : null}\n {snapshot?.spotlight === participant.identity ? (\n <span className=\"mx-meet__badge\">Spotlight</span>\n ) : null}\n </span>\n {participant.handRaised ? <HandIcon width={14} height={14} /> : null}\n {!participant.micEnabled && !isNoteTaker(participant) ? (\n <MicOffIcon width={14} height={14} />\n ) : null}\n <QualityBars quality={participant.quality} />\n <span className=\"mx-meet__anchor\">\n <ControlButton\n label={`More for ${participant.displayName}`}\n active={menuFor === participant.identity}\n onClick={() => setMenuFor(menuFor === participant.identity ? null : participant.identity)}\n >\n <MoreIcon width={16} height={16} />\n </ControlButton>\n {menuFor === participant.identity ? (\n <PersonMenu\n participant={participant}\n placement=\"down\"\n onClose={() => setMenuFor(null)}\n {...(onMessage !== undefined ? { onMessage } : {})}\n />\n ) : null}\n </span>\n </li>\n ))}\n {shown.length === 0 ? <li className=\"mx-meet__panel-note\">Nobody matches “{query}”.</li> : null}\n </ul>\n\n {/* MRF-1: a host decides what the guests in this list will be able to read\n afterwards, WHILE the meeting is running — which is when they know. */}\n {snapshot?.meeting !== null && snapshot?.meeting !== undefined ? (\n <GuestRecordAccessControl meeting={snapshot.meeting} />\n ) : null}\n </PanelShell>\n );\n}\n\n/**\n * EVERYTHING YOU CAN DO ABOUT ONE PERSON (Meet wave 2), in one menu — on their\n * tile and on their People row. An item appears only when it would be honoured:\n * the rank ladder decides moderation (a co-host never sees \"Remove\" on the host),\n * only the host sees \"Make host\", and nobody sees a control that the server\n * would refuse. Removing someone and handing the meeting over NAME THEIR\n * CONSEQUENCE first, inline — never a browser dialog.\n */\nexport function PersonMenu({\n participant,\n onClose,\n onMessage,\n placement = \"down\",\n}: {\n participant: MeetParticipant;\n onClose: () => void;\n onMessage?: (identity: ParticipantIdentity) => void;\n placement?: \"up\" | \"down\";\n}): ReactNode {\n const host = useMeetHost();\n const snapshot = useMeetSnapshot();\n const controls = useHostControls();\n const [mode, setMode] = useState<\"menu\" | \"rename\" | \"report\" | \"remove\" | \"transfer\">(\"menu\");\n const [text, setText] = useState(\"\");\n const self = participant.identity === snapshot?.localIdentity;\n const moderate = controls.canModerate(participant);\n const pinned = snapshot?.pinned === participant.identity;\n const spotlit = snapshot?.spotlight === participant.identity;\n const hasAccount = participant.userId !== null;\n // A refused act keeps its pane open WITH the server's sentence and live\n // buttons — never a confirm that silently stays up (verifier, 2026-09-27).\n const [refused, setRefused] = useState(false);\n const act = (request: Parameters<UseHostControlsResult[\"run\"]>[0]) => {\n setRefused(false);\n void controls.run(request).then((result) => {\n if (result !== null) onClose();\n else setRefused(true);\n });\n };\n const refusal =\n refused && controls.notice?.failed === true ? (\n <ErrorBox as=\"p\" className=\"mx-meet__error\" message={controls.notice.text} operation=\"Change this participant\" origin=\"meet/components\">\n {controls.notice.text}\n </ErrorBox>\n ) : null;\n\n if (mode === \"rename\" || mode === \"report\") {\n const renaming = mode === \"rename\";\n return (\n <Popover label={renaming ? \"Rename\" : \"Report\"} onClose={onClose} placement={placement}>\n <form\n className=\"mx-meet__menu-form\"\n onSubmit={(event) => {\n event.preventDefault();\n if (text.trim().length === 0) return;\n act(\n renaming\n ? { action: \"rename\", identity: participant.identity, name: text.trim() }\n : { action: \"report\", identity: participant.identity, reason: text.trim() },\n );\n }}\n >\n <label className=\"mx-meet__field\">\n <span className=\"mx-meet__field-label\">\n {renaming ? \"Name shown in this meeting\" : `What did ${participant.displayName} do?`}\n </span>\n {renaming ? (\n <input\n className=\"mx-meet__input\"\n autoFocus\n maxLength={80}\n value={text}\n onChange={(event) => setText(event.target.value)}\n />\n ) : (\n <textarea\n className=\"mx-meet__input\"\n autoFocus\n rows={3}\n maxLength={1000}\n value={text}\n onChange={(event) => setText(event.target.value)}\n />\n )}\n </label>\n {refusal}\n <div className=\"mx-meet__menu-actions\">\n <button type=\"button\" className=\"mx-meet__link\" onClick={() => setMode(\"menu\")}>\n Back\n </button>\n <button type=\"submit\" className=\"mx-meet__send\" disabled={text.trim().length === 0 || controls.busy}>\n {renaming ? \"Rename\" : \"Report\"}\n </button>\n </div>\n </form>\n </Popover>\n );\n }\n\n if (mode === \"remove\" || mode === \"transfer\") {\n const removing = mode === \"remove\";\n return (\n <Popover label={removing ? \"Remove\" : \"Make host\"} onClose={onClose} placement={placement}>\n <div className=\"mx-meet__menu-form\">\n <p className=\"mx-meet__confirm-text\">\n {removing\n ? `Remove ${participant.displayName}? They leave immediately and cannot rejoin this meeting.`\n : `Make ${participant.displayName} the host? They get every host control and own this meeting. You stay on as a co-host.`}\n </p>\n {refusal}\n <div className=\"mx-meet__menu-actions\">\n <button type=\"button\" className=\"mx-meet__link\" onClick={() => setMode(\"menu\")}>\n Cancel\n </button>\n <button\n type=\"button\"\n className={removing ? \"mx-meet__send mx-meet__send--danger\" : \"mx-meet__send\"}\n disabled={controls.busy}\n onClick={() =>\n act({ action: removing ? \"remove\" : \"transfer_host\", identity: participant.identity })\n }\n >\n {removing ? \"Remove\" : \"Make host\"}\n </button>\n </div>\n </div>\n </Popover>\n );\n }\n\n return (\n <Popover label={`Options for ${participant.displayName}`} onClose={onClose} placement={placement}>\n <div className=\"mx-meet__menu\" role=\"menu\">\n <MenuItem\n onSelect={() => {\n host?.engine.pin(pinned ? null : participant.identity);\n onClose();\n }}\n >\n <PinIcon width={16} height={16} /> {pinned ? \"Unpin\" : \"Pin for me\"}\n </MenuItem>\n {!self && !participant.isAgent && (onMessage !== undefined || host !== null) ? (\n <MenuItem\n onSelect={() => {\n if (onMessage !== undefined) onMessage(participant.identity);\n else\n host?.store.patch({\n privateChatRequest: { to: participant.identity, at: Date.now() },\n });\n onClose();\n }}\n >\n <ChatIcon width={16} height={16} /> Message privately\n </MenuItem>\n ) : null}\n {controls.isHost ? (\n <MenuItem onSelect={() => act({ action: \"spotlight\", identity: spotlit ? null : participant.identity })}>\n <SpotlightIcon width={16} height={16} /> {spotlit ? \"Remove spotlight\" : \"Spotlight for everyone\"}\n </MenuItem>\n ) : null}\n {moderate ? (\n <>\n <div className=\"mx-meet__menu-sep\" role=\"separator\" />\n {participant.micEnabled ? (\n <MenuItem onSelect={() => act({ action: \"mute\", identity: participant.identity })}>\n <MicOffIcon width={16} height={16} /> Mute\n </MenuItem>\n ) : !participant.isAgent ? (\n <MenuItem onSelect={() => act({ action: \"ask_unmute\", identity: participant.identity })}>\n <MicIcon width={16} height={16} /> Ask to unmute\n </MenuItem>\n ) : null}\n {participant.cameraEnabled ? (\n <MenuItem onSelect={() => act({ action: \"stop_video\", identity: participant.identity })}>\n <CameraOffIcon width={16} height={16} /> Stop video\n </MenuItem>\n ) : null}\n {participant.screenSharing ? (\n <MenuItem onSelect={() => act({ action: \"stop_screen\", identity: participant.identity })}>\n <ScreenShareIcon width={16} height={16} /> Stop screen share\n </MenuItem>\n ) : null}\n {participant.handRaised ? (\n <MenuItem onSelect={() => act({ action: \"lower_hand\", identity: participant.identity })}>\n <HandIcon width={16} height={16} /> Lower hand\n </MenuItem>\n ) : null}\n {hasAccount && !participant.isAgent && participant.role !== \"cohost\" ? (\n <MenuItem onSelect={() => act({ action: \"make_cohost\", identity: participant.identity })}>\n <PeopleIcon width={16} height={16} /> Make co-host\n </MenuItem>\n ) : null}\n {!participant.isAgent ? (\n <MenuItem\n onSelect={() => {\n setText(participant.displayName);\n setMode(\"rename\");\n }}\n >\n <PencilIcon width={16} height={16} /> Rename\n </MenuItem>\n ) : null}\n </>\n ) : null}\n {controls.isOwner && participant.role === \"cohost\" ? (\n <MenuItem onSelect={() => act({ action: \"revoke_cohost\", identity: participant.identity })}>\n <PeopleIcon width={16} height={16} /> Remove co-host\n </MenuItem>\n ) : null}\n {controls.isOwner && !self && hasAccount && !participant.isAgent ? (\n <MenuItem onSelect={() => setMode(\"transfer\")}>\n <SpotlightIcon width={16} height={16} /> Make host\n </MenuItem>\n ) : null}\n {self ? (\n <MenuItem\n onSelect={() => {\n setText(participant.displayName);\n setMode(\"rename\");\n }}\n >\n <PencilIcon width={16} height={16} /> Rename yourself\n </MenuItem>\n ) : null}\n {!self && !participant.isAgent ? (\n <MenuItem\n onSelect={() => {\n setText(\"\");\n setMode(\"report\");\n }}\n >\n <FlagIcon width={16} height={16} /> Report\n </MenuItem>\n ) : null}\n {moderate && !participant.isAgent ? (\n <MenuItem danger onSelect={() => setMode(\"remove\")}>\n <CloseIcon width={16} height={16} /> Remove from meeting\n </MenuItem>\n ) : null}\n </div>\n </Popover>\n );\n}\n\n/* --------------------------------------------------------------- settings */\n\n/**\n * AUDIO, VIDEO AND EFFECTS (Meet wave 2) — the devices in use, a live\n * microphone level, a speaker test, noise suppression and the camera\n * background. Every change applies to the live meeting at once and is\n * remembered in this browser.\n */\nexport function SettingsPanel({ onClose }: { onClose: () => void }): ReactNode {\n const host = useRequiredMeetHost();\n return (\n <PanelShell title=\"Audio, video and effects\" onClose={onClose}>\n <DeviceSettings\n onPick={(kind, deviceId) => {\n host.devices.select(kind, deviceId);\n void host.engine.switchDevice(kind, deviceId);\n }}\n />\n <EffectsSettings />\n </PanelShell>\n );\n}\n\n/** Microphone (with a live level), speaker (with a test), camera. */\nfunction DeviceSettings({\n onPick,\n}: {\n onPick: (kind: \"audioinput\" | \"videoinput\" | \"audiooutput\", deviceId: string) => void;\n}): ReactNode {\n const host = useRequiredMeetHost();\n const devices = useDeviceSnapshot();\n const microphone = devices?.selected.audioinput ?? host.devices.resolve(\"audioinput\");\n const speaker = devices?.selected.audiooutput ?? host.devices.resolve(\"audiooutput\");\n const stream = useMicrophoneStream(microphone);\n const level = useAudioLevel(stream);\n const [testing, setTesting] = useState(false);\n\n useEffect(() => {\n void host.devices.refresh();\n }, [host]);\n\n return (\n <section className=\"mx-meet__section\" aria-label=\"Devices\">\n <DevicePicker kind=\"audioinput\" label=\"Microphone\" onPick={onPick} />\n <div className=\"mx-meet__meter\" role=\"meter\" aria-label=\"Microphone level\" aria-valuemin={0} aria-valuemax={100} aria-valuenow={Math.round(level * 100)}>\n <span style={{ width: `${Math.min(100, Math.round(level * 160))}%` }} />\n </div>\n <DevicePicker kind=\"audiooutput\" label=\"Speaker\" onPick={onPick} />\n <button\n type=\"button\"\n className=\"mx-meet__chip\"\n disabled={testing}\n onClick={() => {\n setTesting(true);\n void playTestSound(speaker).finally(() => setTesting(false));\n }}\n >\n <SpeakerIcon width={14} height={14} /> {testing ? \"Playing…\" : \"Test speaker\"}\n </button>\n <DevicePicker kind=\"videoinput\" label=\"Camera\" onPick={onPick} />\n </section>\n );\n}\n\n/** Noise suppression and the camera background. */\nfunction EffectsSettings({ preview }: { preview?: CameraPreview | null }): ReactNode {\n const effects = useMediaEffects();\n const [error, setError] = useState<string | null>(null);\n const fileRef = useRef<HTMLInputElement | null>(null);\n // Pre-join there is no room driver yet, so the browser itself is asked.\n const supported = effects.backgroundsSupported || preview != null || videoEffectsSupported();\n\n const apply = (next: Partial<MediaEffects>) => {\n setError(null);\n void effects.set(next);\n if (preview != null) {\n const merged = { ...effects.effects, ...next };\n void preview.setEffect(toVideoEffect(merged)).catch(() =>\n setError(\"This browser could not run the background effect.\"),\n );\n }\n };\n\n return (\n <section className=\"mx-meet__section\" aria-label=\"Effects\">\n <label className=\"mx-meet__toggle\">\n <input\n type=\"checkbox\"\n checked={effects.effects.noiseSuppression}\n onChange={(event) => apply({ noiseSuppression: event.target.checked })}\n />\n Noise suppression\n <span className=\"mx-meet__hint\">Filters keyboards, fans and background chatter.</span>\n </label>\n {supported ? (\n <div className=\"mx-meet__field\">\n <span className=\"mx-meet__field-label\">Background</span>\n <div className=\"mx-meet__pills\" role=\"radiogroup\" aria-label=\"Background\">\n {([\"none\", \"blur\", \"image\"] as const).map((kind) => (\n <button\n key={kind}\n type=\"button\"\n role=\"radio\"\n aria-checked={effects.effects.background === kind}\n className={\n effects.effects.background === kind ? \"mx-meet__pill mx-meet__pill--on\" : \"mx-meet__pill\"\n }\n onClick={() => {\n if (kind === \"image\") {\n fileRef.current?.click();\n return;\n }\n apply({ background: kind });\n }}\n >\n {kind === \"none\" ? \"None\" : kind === \"blur\" ? \"Blur\" : \"Picture…\"}\n </button>\n ))}\n </div>\n <input\n ref={fileRef}\n type=\"file\"\n accept=\"image/*\"\n hidden\n onChange={(event) => {\n const file = event.target.files?.[0];\n event.target.value = \"\";\n if (file === undefined) return;\n void shrinkImage(file)\n .then((url) => apply({ background: \"image\", backgroundImage: url }))\n .catch(() => setError(\"That picture could not be read. Try a JPEG or PNG.\"));\n }}\n />\n {error !== null ? <p className=\"mx-meet__error\">{error}</p> : null}\n </div>\n ) : null}\n </section>\n );\n}\n\nfunction toVideoEffect(effects: MediaEffects): VideoEffect {\n if (effects.background === \"blur\") return { kind: \"blur\" };\n if (effects.background === \"image\" && effects.backgroundImage !== null) {\n return { kind: \"image\", imageUrl: effects.backgroundImage };\n }\n return { kind: \"none\" };\n}\n\n/**\n * A picked background, scaled to 1280 px wide as a JPEG data URL — small enough\n * to remember in this browser (a `blob:` URL dies with the tab), large enough\n * for a 720p camera.\n */\nasync function shrinkImage(file: File): Promise<string> {\n const url = URL.createObjectURL(file);\n try {\n const image = new Image();\n image.src = url;\n await image.decode();\n const scale = Math.min(1, 1280 / image.naturalWidth);\n const canvas = document.createElement(\"canvas\");\n canvas.width = Math.round(image.naturalWidth * scale);\n canvas.height = Math.round(image.naturalHeight * scale);\n const context = canvas.getContext(\"2d\");\n if (context === null) throw new Error(\"no 2d context\");\n context.drawImage(image, 0, 0, canvas.width, canvas.height);\n return canvas.toDataURL(\"image/jpeg\", 0.85);\n } finally {\n URL.revokeObjectURL(url);\n }\n}\n\n/** A short two-tone chime through the chosen speaker. */\nasync function playTestSound(sinkId: string | null): Promise<void> {\n const Context = (globalThis as { AudioContext?: typeof AudioContext }).AudioContext;\n if (Context === undefined) return;\n const context = new Context();\n const destination = context.createMediaStreamDestination();\n const gain = context.createGain();\n gain.gain.value = 0.2;\n gain.connect(destination);\n for (const [frequency, start] of [\n [660, 0],\n [880, 0.25],\n ] as const) {\n const oscillator = context.createOscillator();\n oscillator.frequency.value = frequency;\n oscillator.connect(gain);\n oscillator.start(context.currentTime + start);\n oscillator.stop(context.currentTime + start + 0.22);\n }\n const audio = new Audio();\n audio.srcObject = destination.stream;\n const sinkable = audio as HTMLAudioElement & { setSinkId?: (id: string) => Promise<void> };\n if (sinkId !== null && sinkId !== \"default\" && sinkable.setSinkId !== undefined) {\n await sinkable.setSinkId(sinkId).catch(() => undefined);\n }\n await audio.play().catch(() => undefined);\n await new Promise((resolve) => setTimeout(resolve, 700));\n audio.pause();\n await context.close();\n}\n\n/** A microphone stream for the level meter only — closed with the component. */\nfunction useMicrophoneStream(deviceId: string | null | \"off\"): MediaStream | null {\n const [stream, setStream] = useState<MediaStream | null>(null);\n useEffect(() => {\n if (deviceId === \"off\") return undefined;\n let live = true;\n let opened: MediaStream | null = null;\n const media = (globalThis as { navigator?: Navigator }).navigator?.mediaDevices;\n if (media === undefined) return undefined;\n void media\n .getUserMedia({ audio: deviceId === null ? true : { deviceId: { exact: deviceId } } })\n .then((next) => {\n if (!live) {\n next.getTracks().forEach((track) => track.stop());\n return;\n }\n opened = next;\n setStream(next);\n })\n .catch(() => setStream(null));\n return () => {\n live = false;\n opened?.getTracks().forEach((track) => track.stop());\n setStream(null);\n };\n }, [deviceId]);\n return stream;\n}\n\n/** The waiting room. Rendered for hosts only — a participant sees nothing. */\nexport function LobbyPanel(): ReactNode {\n const lobby = useLobby();\n if (!lobby.canAdmit || lobby.waiting.length === 0) return null;\n return (\n <section className=\"mx-meet__lobby\" aria-label=\"Waiting room\">\n <header className=\"mx-meet__lobby-head\">\n <h3 className=\"mx-meet__lobby-title\">\n {lobby.waiting.length === 1\n ? \"1 person is waiting\"\n : `${lobby.waiting.length} people are waiting`}\n </h3>\n <button type=\"button\" className=\"mx-meet__link\" onClick={() => void lobby.admitAll()}>\n Admit all\n </button>\n </header>\n <ul className=\"mx-meet__lobby-list\">\n {lobby.waiting.map((entry) => (\n <li key={entry.identity} className=\"mx-meet__lobby-row\">\n <Avatar name={entry.displayName} url={entry.avatarUrl} size={32} />\n <span className=\"mx-meet__person-name\">\n {entry.displayName}\n {entry.userId === null ? <span className=\"mx-meet__badge\">Guest</span> : null}\n </span>\n <ControlButton label={`Admit ${entry.displayName}`} onClick={() => void lobby.admit(entry)}>\n <CheckIcon width={16} height={16} />\n </ControlButton>\n <ControlButton\n label={`Deny ${entry.displayName}`}\n danger\n onClick={() => void lobby.deny(entry)}\n >\n <CloseIcon width={16} height={16} />\n </ControlButton>\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\n/**\n * THE NOTE-TAKER'S STATE, on screen, with the server's own words.\n *\n * 🚨 NEVER A SPINNER. Every one of the five states (D9/MRI-A2) has a sentence,\n * and a refused dispatch shows the SERVER's `reason` and `remedy` verbatim —\n * \"no worker is registered under matrx-note-taker\", and what to do about it.\n * Through 0.2.1 a failed dispatch threw and the panel showed a remedy with no\n * state behind it; a person could not tell \"it refused\" from \"it is coming\".\n */\nfunction NoteTakerRow(): ReactNode {\n const ai = useMeetAi();\n const status = ai.noteTaker;\n const duplicateError =\n status.refusal !== null &&\n ai.error !== null &&\n status.refusal.reason === ai.error.message &&\n status.refusal.remedy === ai.error.remedy;\n return (\n <section className=\"mx-meet__note-taker\" aria-label=\"Note-taker\">\n <p className={`mx-meet__note-taker-state mx-meet__note-taker-state--${status.state}`}>\n <span className=\"mx-meet__note-taker-dot\" aria-hidden=\"true\" />\n {ai.noteTakerLabel}\n </p>\n {status.detail !== null ? (\n <p className=\"mx-meet__panel-note\">{status.detail}</p>\n ) : null}\n\n {/* THE REFUSAL, VERBATIM. Not summarized, not replaced by a house\n sentence, and not hidden behind a retry that would refuse again. */}\n {status.refusal !== null ? (\n <ErrorBox as=\"div\" className=\"mx-meet__refusal\" error={status.refusal} operation=\"Join this meeting\" origin=\"meet/components\">\n <p className=\"mx-meet__refusal-reason\">{status.refusal.reason}</p>\n {status.refusal.remedy.length > 0 ? (\n <p className=\"mx-meet__refusal-remedy\">{status.refusal.remedy}</p>\n ) : null}\n </ErrorBox>\n ) : null}\n\n {ai.error !== null && !duplicateError ? (\n <ErrorBox as=\"div\" className=\"mx-meet__refusal\" error={ai.error} operation=\"Run the meeting assistant\" origin=\"meet/components\">\n <p className=\"mx-meet__refusal-reason\">{ai.error.message}</p>\n <p className=\"mx-meet__refusal-remedy\">{ai.error.remedy}</p>\n </ErrorBox>\n ) : null}\n\n {/* A control an actor cannot use is ABSENT (no dead ends). A guest and a\n non-host see the STATE and no buttons at all. */}\n {ai.canControlNoteTaker ? (\n status.state === \"transcribing\" ||\n status.state === \"joining\" ||\n status.state === \"handoff_pending\" ? (\n <button\n type=\"button\"\n className=\"mx-meet__link\"\n onClick={() => void ai.stopNoteTaker()}\n >\n Dismiss the note-taker\n </button>\n ) : (\n <button\n type=\"button\"\n className=\"mx-meet__primary\"\n onClick={() => void ai.startNoteTaker()}\n >\n Start note-taker\n </button>\n )\n ) : null}\n </section>\n );\n}\n\nfunction NoteList({\n title,\n notes,\n empty,\n}: {\n title: string;\n notes: readonly { id: string; text: string; assigneeDisplayName?: string | null }[];\n empty: string;\n}): ReactNode {\n return (\n <section className=\"mx-meet__note-group\" aria-label={title}>\n <h3 className=\"mx-meet__note-group-title\">{title}</h3>\n {notes.length === 0 ? (\n <p className=\"mx-meet__panel-note\">{empty}</p>\n ) : (\n <ul className=\"mx-meet__notes\">\n {notes.map((note) => (\n <li key={note.id} className=\"mx-meet__note\">\n {note.text}\n {/* D18: a guest never gets an `assignee_user_id`, so the name is\n read from the row's metadata — an action item whose owner has\n no name is an action item nobody owns. */}\n {note.assigneeDisplayName !== undefined &&\n note.assigneeDisplayName !== null ? (\n <span className=\"mx-meet__assignee\">{note.assigneeDisplayName}</span>\n ) : null}\n </li>\n ))}\n </ul>\n )}\n </section>\n );\n}\n\n/**\n * THE MEETING ASSISTANT (R4). The note-taker's state, what the meeting has\n * decided so far, the wrap-up, and a question box whose answer arrives token by\n * token.\n *\n * Nothing on this panel is computed here: notes, decisions and action items are\n * durable rows delivered by Postgres Changes, and the answer is streamed from\n * `/intelligence/ask`, which builds it from those same rows. The captions this\n * client can see are never sent anywhere (D16).\n */\nexport function AiPanel({ onClose }: { onClose: () => void }): ReactNode {\n const ai = useMeetAi();\n const [question, setQuestion] = useState(\"\");\n\n return (\n <PanelShell title=\"Meeting assistant\" onClose={onClose}>\n <NoteTakerRow />\n\n {ai.summary !== null ? (\n <section className=\"mx-meet__note-group\" aria-label=\"Summary\">\n <h3 className=\"mx-meet__note-group-title\">Summary</h3>\n <p className=\"mx-meet__summary\">{ai.summary.text}</p>\n </section>\n ) : null}\n\n {/*\n THE WRAP-UP, ANNOUNCED IN THE ROOM (MRI-A12). It says the pass FINISHED,\n which is the one thing the notes above cannot say for themselves — a\n panel with no summary is otherwise indistinguishable from a summary that\n is still being written. It is absent, never a placeholder, when nothing\n was announced: on the ordinary ending path the room is deleted before the\n pass runs, and the summary is read on the post-meeting record instead.\n */}\n {ai.wrapUp !== null ? (\n <p className=\"mx-meet__wrap-up-notice\" role=\"status\">\n The wrap-up is written — {ai.wrapUp.noteIds.length}{\" \"}\n {ai.wrapUp.noteIds.length === 1 ? \"entry\" : \"entries\"} from{\" \"}\n {ai.wrapUp.segmentCount}{\" \"}\n {ai.wrapUp.segmentCount === 1 ? \"transcript line\" : \"transcript lines\"}.\n </p>\n ) : null}\n\n <NoteList\n title=\"Notes\"\n notes={ai.notes}\n empty=\"Notes appear here as the meeting goes on.\"\n />\n <NoteList\n title=\"Decisions\"\n notes={ai.decisions}\n empty=\"Nothing has been decided yet.\"\n />\n <NoteList\n title=\"Action items\"\n notes={ai.actionItems}\n empty=\"No action items yet.\"\n />\n\n {ai.transcript.length > 0 ? (\n <section className=\"mx-meet__note-group\" aria-label=\"Transcript\">\n <h3 className=\"mx-meet__note-group-title\">Transcript</h3>\n <ul className=\"mx-meet__transcript\">\n {ai.transcript.map((line) => (\n <li\n key={line.id}\n className={\n line.final && line.source === \"record\"\n ? \"mx-meet__line\"\n : \"mx-meet__line mx-meet__line--interim\"\n }\n >\n <strong>{line.speaker}</strong>\n <span>{line.text}</span>\n </li>\n ))}\n </ul>\n </section>\n ) : null}\n\n <form\n className=\"mx-meet__composer\"\n onSubmit={(event) => {\n event.preventDefault();\n const asked = question;\n setQuestion(\"\");\n void ai.ask(asked);\n }}\n >\n <input\n className=\"mx-meet__input\"\n value={question}\n onChange={(event) => setQuestion(event.target.value)}\n placeholder=\"Ask about this meeting\"\n aria-label=\"Ask about this meeting\"\n />\n <button type=\"submit\" className=\"mx-meet__send\" disabled={ai.asking}>\n {ai.asking ? \"Asking…\" : \"Ask\"}\n </button>\n </form>\n\n {/* THE SERVER'S PHASE, not a spinner of our invention. */}\n {ai.asking && ai.phase !== null ? (\n <p className=\"mx-meet__panel-note\" role=\"status\">\n {ai.phase}\n </p>\n ) : null}\n {ai.answer !== null ? <p className=\"mx-meet__answer\">{ai.answer}</p> : null}\n {/* WHAT THE ANSWER WAS BUILT FROM. The server measures it; a truncated\n transcript is stated rather than quietly answered around. */}\n {ai.answer !== null && ai.coverage !== null ? (\n <p className=\"mx-meet__coverage\">\n Answered from {ai.coverage.segmentsUsed} of {ai.coverage.segmentsTotal} transcript\n lines\n {ai.coverage.truncated ? \" (the oldest were left out)\" : \"\"}.\n </p>\n ) : null}\n {/* THE REMEDY, not a shrug — and rendered by THIS hook instance, because\n `useMeetAi()` holds its own ask state per component. */}\n {ai.error !== null ? (\n <ErrorBox as=\"div\" className=\"mx-meet__refusal\" error={ai.error} operation=\"Run the meeting assistant\" origin=\"meet/components\">\n <p className=\"mx-meet__refusal-reason\">{ai.error.message}</p>\n <p className=\"mx-meet__refusal-remedy\">{ai.error.remedy}</p>\n </ErrorBox>\n ) : null}\n </PanelShell>\n );\n}\n\n/**\n * LIVE CAPTIONS. The last few lines, over the stage, for anyone who reads\n * faster than they hear.\n *\n * They are HINTS (D16) — the durable segment replaces the line it captioned as\n * soon as the row lands — so an unsettled line renders differently from a\n * settled one and nothing downstream ever reads this list.\n */\nexport function Captions({ lines = 3 }: { lines?: number }): ReactNode {\n const ai = useMeetAi();\n const visible = ai.transcript.slice(-lines);\n if (visible.length === 0) return null;\n return (\n <div className=\"mx-meet__captions\" aria-live=\"polite\" aria-label=\"Live captions\">\n {visible.map((line) => (\n <p\n key={line.id}\n className={\n line.final ? \"mx-meet__caption\" : \"mx-meet__caption mx-meet__caption--interim\"\n }\n >\n <strong>{line.speaker}</strong> {line.text}\n </p>\n ))}\n </div>\n );\n}\n\n/**\n * CONSENT IS NOT A PROP (README rule 8, D10).\n *\n * Whenever an agent participant is in the room, EVERY participant sees this —\n * host, member and guest alike. There is no prop that hides it and no host code\n * involved: through 0.2.1 the first real consumer had to write this banner\n * itself by reading `isAgent` off the roster, which is exactly the massage C22\n * forbids.\n */\nexport function ConsentNotice(): ReactNode {\n const notice = useConsentNotice();\n if (notice === null) return null;\n return (\n <p className=\"mx-meet__consent\" role=\"status\">\n {notice}\n </p>\n );\n}\n\n/**\n * LISTEN-ONLY ATTENDANCE, said out loud. Shown whenever the local participant\n * is in the room publishing no microphone — whether they chose that or the\n * browser refused. When it was refused, the browser's own reason and the remedy\n * are shown too, because \"others can't hear you\" without \"and here is why\"\n * leaves someone clicking a mute button that cannot work.\n */\nexport function AttendanceNotice(): ReactNode {\n const media = useLocalMedia();\n const notice = listenOnlyNotice(media);\n if (notice === null) return null;\n const refused = media.microphone.unavailable;\n return (\n <p className=\"mx-meet__banner mx-meet__banner--attendance\" role=\"status\">\n {notice}\n {refused === null ? null : <span className=\"mx-meet__remedy\">{refused.remedy}</span>}\n </p>\n );\n}\n\n/* --------------------------------------------------------------- pre-join */\n\nexport function PreJoin(props: {\n roomName: RoomName;\n meetingId?: string;\n slug?: string;\n onJoined?: () => void;\n}): ReactNode {\n // THE GUARD, not a throw. See <InertNotice>.\n const host = useMeetHost();\n if (host === null) return <InertNotice what=\"This meeting\" />;\n return <PreJoinBody {...props} host={host} />;\n}\n\nfunction PreJoinBody({\n roomName,\n meetingId,\n slug,\n onJoined,\n host,\n}: {\n roomName: RoomName;\n meetingId?: string;\n slug?: string;\n onJoined?: () => void;\n host: MeetHost;\n}): ReactNode {\n const room = useRoom();\n const devices = useDeviceSnapshot();\n const recording = useRecording();\n const effects = useMediaEffects();\n const { notice } = useModerationNotice();\n const [mode, setMode] = useState<CallMode>(\"video\");\n // Attendance is not contingent on a device (see core/attendance.ts), so this\n // is an ordinary choice, not a gate. Unchecking it joins listen-only; leaving\n // it checked and having the browser refuse ALSO joins, listen-only, with the\n // refusal's own remedy shown in the room.\n const [microphone, setMicrophone] = useState(true);\n const [joining, setJoining] = useState(false);\n const camera = devices?.selected.videoinput ?? host.devices.resolve(\"videoinput\");\n const mic = devices?.selected.audioinput ?? host.devices.resolve(\"audioinput\");\n const preview = useCameraPreview(mode === \"video\" ? camera : undefined, effects.effects);\n const micStream = useMicrophoneStream(microphone ? mic : \"off\");\n const level = useAudioLevel(micStream);\n const [speakerTesting, setSpeakerTesting] = useState(false);\n\n useEffect(() => {\n void host.devices.refresh();\n }, [host]);\n\n return (\n <div className=\"mx-meet__prejoin\">\n <div className=\"mx-meet__preview\">\n {mode === \"video\" && preview.preview !== null ? (\n <video\n className=\"mx-meet__video mx-meet__video--mirror\"\n autoPlay\n playsInline\n muted\n ref={(element) => {\n if (element !== null) preview.preview?.attach(element);\n }}\n />\n ) : (\n <div className=\"mx-meet__tile-placeholder\">\n <Avatar name={host.identity.displayName} url={host.identity.avatarUrl} size={96} />\n </div>\n )}\n {mode === \"video\" && preview.error !== null ? (\n <p className=\"mx-meet__preview-note\">{preview.error}</p>\n ) : null}\n {microphone && micStream !== null ? (\n <div className=\"mx-meet__meter mx-meet__meter--preview\" role=\"meter\" aria-label=\"Microphone level\" aria-valuemin={0} aria-valuemax={100} aria-valuenow={Math.round(level * 100)}>\n <span style={{ width: `${Math.min(100, Math.round(level * 160))}%` }} />\n </div>\n ) : null}\n </div>\n\n <div className=\"mx-meet__prejoin-panel\">\n <h1 className=\"mx-meet__prejoin-title\">Ready to join?</h1>\n\n {notice?.kind === \"removed\" ? <p className=\"mx-meet__warning\">{notice.text}</p> : null}\n\n {devices?.labelsHidden === true ? (\n <p className=\"mx-meet__panel-note\">\n Your browser is hiding device names until you allow camera and microphone access.\n <button\n type=\"button\"\n className=\"mx-meet__link\"\n onClick={() => {\n void host.devices.requestPermission({ audio: true, video: true });\n }}\n >\n Allow access\n </button>\n </p>\n ) : null}\n\n {/* A FALLBACK ANNOUNCES ITSELF — an unplugged headset never silently\n becomes the laptop mic. */}\n {devices?.fallbackNotice != null ? (\n <p className=\"mx-meet__warning\">{devices.fallbackNotice}</p>\n ) : null}\n\n <DevicePicker kind=\"audioinput\" label=\"Microphone\" />\n <div className=\"mx-meet__field-row\">\n <DevicePicker kind=\"audiooutput\" label=\"Speaker\" />\n <button\n type=\"button\"\n className=\"mx-meet__chip\"\n disabled={speakerTesting}\n onClick={() => {\n setSpeakerTesting(true);\n void playTestSound(devices?.selected.audiooutput ?? host.devices.resolve(\"audiooutput\")).finally(\n () => setSpeakerTesting(false),\n );\n }}\n >\n <SpeakerIcon width={14} height={14} /> {speakerTesting ? \"Playing…\" : \"Test\"}\n </button>\n </div>\n <DevicePicker kind=\"videoinput\" label=\"Camera\" />\n <EffectsSettings preview={preview.preview} />\n\n {recording.consentNotice !== null ? (\n <p className=\"mx-meet__consent\">{recording.consentNotice}</p>\n ) : null}\n\n <div className=\"mx-meet__prejoin-actions\">\n <label className=\"mx-meet__toggle\">\n <input\n type=\"checkbox\"\n checked={mode === \"video\"}\n onChange={(event) => setMode(event.target.checked ? \"video\" : \"audio\")}\n />\n Join with video\n </label>\n <label className=\"mx-meet__toggle\">\n <input\n type=\"checkbox\"\n checked={microphone}\n onChange={(event) => setMicrophone(event.target.checked)}\n />\n Join with microphone\n </label>\n <button\n type=\"button\"\n className=\"mx-meet__primary\"\n onClick={() => {\n setJoining(true);\n // The preview hands the camera back before the room takes it.\n preview.release();\n void room\n .join({\n roomName,\n mode,\n microphone,\n ...(meetingId !== undefined ? { meetingId } : {}),\n ...(slug !== undefined ? { slug } : {}),\n })\n .then(() => onJoined?.())\n // The failure is ON SCREEN (room.failure, the server's sentence); an\n // unhandled rejection only added a page error nobody can act on.\n .catch(() => undefined)\n .finally(() => setJoining(false));\n }}\n >\n {joining ? \"Joining…\" : \"Join now\"}\n </button>\n </div>\n\n {room.failure !== null ? (\n <p className=\"mx-meet__error\">\n {room.failure.message}\n <span className=\"mx-meet__remedy\">{room.failure.remedy}</span>\n </p>\n ) : null}\n </div>\n </div>\n );\n}\n\n/**\n * The pre-join camera, WITH the chosen background — the same SDK track and\n * processor the room uses. `undefined` device = camera not wanted (no preview,\n * no light). A refused camera is a sentence, never a black box.\n */\nfunction useCameraPreview(\n deviceId: string | null | undefined,\n effects: MediaEffects,\n): { preview: CameraPreview | null; error: string | null; release: () => void } {\n const [preview, setPreview] = useState<CameraPreview | null>(null);\n const [error, setError] = useState<string | null>(null);\n const current = useRef<CameraPreview | null>(null);\n const initialEffect = useRef(toVideoEffect(effects));\n initialEffect.current = toVideoEffect(effects);\n useEffect(() => {\n if (deviceId === undefined) return undefined;\n let live = true;\n setError(null);\n void createCameraPreview(deviceId, initialEffect.current)\n .then((created) => {\n if (!live) {\n created.stop();\n return;\n }\n current.current = created;\n setPreview(created);\n })\n .catch((thrown: unknown) => {\n if (!live) return;\n const failure = thrown as { message?: string; remedy?: string };\n // The person reads the sentence and its remedy — never the operation tag\n // (\"meet.cameraPreview: …\") a diagnostic carries.\n const message = (failure.message ?? \"\").replace(/^meet\\.[A-Za-z.()]+:\\s*/, \"\");\n const sentence = message.length > 0 ? message.charAt(0).toUpperCase() + message.slice(1) : \"\";\n setError([sentence, failure.remedy].filter(Boolean).join(\". \") || \"The camera did not start.\");\n });\n return () => {\n live = false;\n current.current?.stop();\n current.current = null;\n setPreview(null);\n };\n }, [deviceId]);\n return {\n preview,\n error,\n release: () => {\n current.current?.stop();\n current.current = null;\n setPreview(null);\n },\n };\n}\n\nfunction DevicePicker({\n kind,\n label,\n onPick,\n}: {\n kind: \"audioinput\" | \"videoinput\" | \"audiooutput\";\n label: string;\n /** In the room: also switch the live device. Pre-join: the choice is applied on join. */\n onPick?: (kind: \"audioinput\" | \"videoinput\" | \"audiooutput\", deviceId: string) => void;\n}): ReactNode {\n const host = useRequiredMeetHost();\n const devices = useDeviceSnapshot();\n const list = devices?.devices[kind] ?? [];\n // A browser that cannot route audio output (Safari, Firefox without the flag)\n // lists no outputs — the picker is then absent, never a select that lies.\n if (list.length === 0) return null;\n return (\n <label className=\"mx-meet__field\">\n <span className=\"mx-meet__field-label\">{label}</span>\n <select\n className=\"mx-meet__select\"\n value={devices?.selected[kind] ?? host.devices.resolve(kind) ?? \"\"}\n onChange={(event) => {\n if (onPick !== undefined) onPick(kind, event.target.value);\n else host.devices.select(kind, event.target.value);\n }}\n >\n {list.map((device) => (\n <option key={device.deviceId} value={device.deviceId}>\n {device.label.length > 0 ? device.label : `${label} (name hidden)`}\n </option>\n ))}\n </select>\n </label>\n );\n}\n\n/* ----------------------------------------------------------- meeting room */\n\nexport function MeetingRoom(props: {\n roomName: RoomName;\n meetingId?: string;\n slug?: string;\n /**\n * The meeting the host already resolved, when it has one (MRI-D2).\n *\n * 🚨 THIS IS WHAT MAKES AN ENDED MEETING WORK FOR A GUEST. Only\n * `meet_meeting_by_slug` is granted to `anon`; the `meet_meetings` TABLE is\n * not, so the durable-feed backfill — a table read — is refused for a\n * link-follower and `snapshot.meeting` stays null for them forever. A\n * consumer that resolved the slug through the RPC (every consumer does, to\n * get the room name) passes the row here, and the record renders for exactly\n * the reader who has nothing else.\n */\n meeting?: MeetingRecord;\n onLeave?: () => void;\n /**\n * A HOST-PROVIDED control for the in-meeting header — the host app's own\n * affordances that belong to the meeting (matrx-frontend puts its\n * Intelligence icon for the meeting's AI jobs here). Rendered in the header\n * row of the live room only; the pre-join, lobby and record screens carry\n * none. The package never inspects it, and styles nothing inside it.\n */\n headerControls?: ReactNode;\n}): ReactNode {\n // THE GUARD, not a throw. See <InertNotice>.\n const host = useMeetHost();\n if (host === null) {\n return (\n <div className=\"mx-meet\">\n <InertNotice what=\"This meeting\" />\n </div>\n );\n }\n return <MeetingRoomBody {...props} host={host} />;\n}\n\nfunction MeetingRoomBody({\n roomName,\n meetingId,\n slug,\n meeting: given,\n onLeave,\n headerControls,\n host,\n}: {\n roomName: RoomName;\n meetingId?: string;\n slug?: string;\n meeting?: MeetingRecord;\n onLeave?: () => void;\n headerControls?: ReactNode;\n host: MeetHost;\n}): ReactNode {\n const snapshot = useMeetSnapshot();\n const isHost = useIsHost();\n const elapsed = useElapsed(snapshot?.meeting?.startedAt ?? null);\n const phase = snapshot?.phase ?? \"idle\";\n\n useEffect(() => {\n host.meetings.watch(roomName);\n }, [host, roomName]);\n\n // 🚨 THE RESOLVED ROW SEEDS THE SNAPSHOT, AND THAT IS THE WHOLE GUEST LANE\n // (MRI-A12). `snapshot.meeting` was only ever written by the Postgres Changes\n // subscription and its backfill — both of which read the `meet_meetings`\n // TABLE, which `anon` cannot select. So for a session-less guest it stayed\n // null FOREVER, and everything keyed on it silently did not exist: no\n // Meeting-assistant control (so no notes, decisions or action items on\n // screen), no live captions (`room.ts` drops a caption with no meeting to\n // reconcile it against), and no room event that has to be matched to this\n // meeting. A guest sat in a working room with none of the meeting's\n // intelligence, and nothing said so.\n //\n // The consumer already resolved the row through `meet_meeting_by_slug` — the\n // one door that IS granted to `anon` — and hands it here. Seeding it is what\n // makes \"the resolved row travels with the room\" true rather than aspirational.\n // Written ONCE, only when the store has nothing: the durable feed's copy is\n // the record and must never be overwritten by the prop it started from.\n useEffect(() => {\n if (given === undefined) return;\n if (host.store.snapshot().meeting !== null) return;\n host.store.patch({ meeting: given, locked: given.locked });\n }, [host, given]);\n\n // THE DURABLE FEED. Transcript rows, notes and the meeting row itself (which\n // carries the note-taker's state) arrive by Postgres Changes, and the\n // subscription's own backfill reads all three on open and after every\n // reconnect — realtime has no replay, so reconnecting IS re-reading.\n const watchedId = meetingId ?? snapshot?.meeting?.id ?? null;\n useEffect(() => {\n if (watchedId === null) return;\n host.meetings.watchMeeting(asMeetingId(watchedId));\n }, [host, watchedId]);\n\n // 🚨 AN ENDED MEETING IS A RECORD, NOT A PRE-JOIN SCREEN (MRI-D2).\n //\n // The live snapshot wins when it has one (a meeting that ends WHILE somebody\n // is on this screen flips to the record on the same realtime event that\n // stamped `ended_at`); the resolved row the consumer handed us is the\n // fallback, and it is the only one a guest ever has. Before this, the durable\n // link resolved to `<PreJoin>` for a room that no longer existed — offering\n // to join a finished meeting, with the whole wrap-up unreachable.\n const record = snapshot?.meeting ?? given ?? null;\n if (hasEnded(record) && phase !== \"connected\" && phase !== \"reconnecting\") {\n return <MeetingRecordView meeting={record as MeetingRecord} />;\n }\n\n if (phase === \"idle\" || phase === \"failed\" || phase === \"left\") {\n return (\n <div className=\"mx-meet\">\n <PreJoin\n roomName={roomName}\n {...(meetingId !== undefined ? { meetingId } : {})}\n {...(slug !== undefined ? { slug } : {})}\n />\n </div>\n );\n }\n\n if (phase === \"lobby\") {\n return (\n <div className=\"mx-meet mx-meet--lobby\">\n <WaitingRoom roomName={roomName} host={host} />\n </div>\n );\n }\n\n return (\n <div className=\"mx-meet\">\n <ConsentNotice />\n <AttendanceNotice />\n <header className=\"mx-meet__header\">\n <h1 className=\"mx-meet__title\">{snapshot?.meeting?.title ?? \"Meeting\"}</h1>\n <span className=\"mx-meet__meta\">\n {participantSummary(snapshot?.participants ?? [])}\n {elapsed > 0 ? ` · ${formatDurationMs(elapsed)}` : \"\"}\n </span>\n <RecordingIndicator />\n {snapshot?.locked === true ? (\n <span className=\"mx-meet__badge\">\n <LockIcon width={12} height={12} /> Locked\n </span>\n ) : null}\n {headerControls !== undefined && headerControls !== null ? (\n <span className=\"mx-meet__header-controls\" data-meet-header-controls=\"\">\n {headerControls}\n </span>\n ) : null}\n {isHost ? <HostMenu /> : null}\n </header>\n\n {/* A reconnect is VISIBLE. A frozen tile with no explanation is\n indistinguishable from a crashed app. */}\n {phase === \"reconnecting\" ? (\n <p className=\"mx-meet__banner\" role=\"status\">\n Reconnecting…\n </p>\n ) : null}\n\n <Stage />\n <Captions />\n <ControlBar {...(onLeave !== undefined ? { onLeave } : {})} />\n </div>\n );\n}\n\nfunction WaitingRoom({ roomName, host }: { roomName: RoomName; host: MeetHost }): ReactNode {\n const knocked = useRef(false);\n useEffect(() => {\n if (knocked.current) return;\n knocked.current = true;\n host.meetings.knock(roomName);\n }, [host, roomName]);\n\n return (\n <div className=\"mx-meet__waiting\">\n <Avatar name={host.identity.displayName} url={host.identity.avatarUrl} size={72} />\n <h1 className=\"mx-meet__prejoin-title\">Waiting for the host to let you in</h1>\n <p className=\"mx-meet__empty-body\">\n You are in the waiting room as {host.identity.displayName}. You will join automatically\n once you are admitted.\n </p>\n </div>\n );\n}\n\nexport function HostMenu(): ReactNode {\n const host = useRequiredMeetHost();\n const snapshot = useMeetSnapshot();\n const end = useEndMeeting();\n // ENDING A MEETING IS DESTRUCTIVE AND IRREVERSIBLE, so the click that does it\n // names the consequence first — inline, never `window.confirm` (no browser\n // dialogs).\n const [confirmingEnd, setConfirmingEnd] = useState(false);\n const locked = snapshot?.locked === true;\n return (\n <div className=\"mx-meet__host-menu\">\n <button\n type=\"button\"\n className=\"mx-meet__link\"\n onClick={() => {\n void host.meetings.setLock(!locked);\n }}\n >\n {locked ? \"Unlock meeting\" : \"Lock meeting\"}\n </button>\n {/* ENDING IT IS A HOST POWER AND A SERVER DECISION (MRI-A6). The button\n is real; a server that does not serve the route yet earns a SENTENCE\n rather than a dead control or a silent no-op. */}\n {end.canEnd ? (\n confirmingEnd ? (\n <span className=\"mx-meet__confirm\" role=\"group\" aria-label=\"End this meeting?\">\n <span className=\"mx-meet__confirm-text\">\n End it for everyone? Every participant is disconnected, the note-taker stops, and the\n wrap-up is written. Nobody can rejoin this meeting afterwards.\n </span>\n <button\n type=\"button\"\n className=\"mx-meet__link mx-meet__link--danger\"\n onClick={() => {\n setConfirmingEnd(false);\n void end.end();\n }}\n >\n End it\n </button>\n <button\n type=\"button\"\n className=\"mx-meet__link\"\n onClick={() => setConfirmingEnd(false)}\n >\n Keep it running\n </button>\n </span>\n ) : (\n <button\n type=\"button\"\n className=\"mx-meet__link mx-meet__link--danger\"\n onClick={() => setConfirmingEnd(true)}\n >\n {end.ending ? \"Ending…\" : \"End meeting for everyone\"}\n </button>\n )\n ) : null}\n {end.notice !== null ? (\n <span className=\"mx-meet__notice\" role=\"status\">\n {end.notice}\n </span>\n ) : null}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ calls */\n\n/** Drop this next to a person and calling works. That is the whole contract. */\nexport function CallButton({\n person,\n mode = \"video\",\n children,\n}: {\n person: CallablePerson;\n mode?: CallMode;\n children?: ReactNode;\n}): ReactNode {\n const calls = useCalls();\n // A guest identity renders NOTHING — not a disabled button (D6, no dead ends).\n if (!calls.canCall) return null;\n return (\n <button\n type=\"button\"\n className=\"mx-meet__call-button\"\n onClick={() => {\n void calls.call([person.userId], mode);\n }}\n aria-label={`Call ${person.displayName}`}\n >\n {children ?? <PhoneIcon width={18} height={18} />}\n </button>\n );\n}\n\n/**\n * Mount ONCE, high in the tree. Every incoming call rings here, on whatever\n * surface the user is on (R2).\n */\nexport function IncomingCallHost(): ReactNode {\n const calls = useCalls();\n if (calls.incoming.length === 0) return null;\n return (\n <div className=\"mx-meet__ringing-stack\">\n {calls.incoming.map((invite) => (\n <IncomingCallCard key={invite.id} invite={invite} />\n ))}\n </div>\n );\n}\n\nexport function IncomingCallCard({ invite }: { invite: CallInvite }): ReactNode {\n const calls = useCalls();\n return (\n <section className=\"mx-meet__ringing\" role=\"alertdialog\" aria-label=\"Incoming call\">\n <Avatar name={invite.callerName} url={invite.callerAvatarUrl} size={56} />\n <div className=\"mx-meet__ringing-text\">\n <strong>{invite.callerName}</strong>\n <span>{invite.mode === \"video\" ? \"Incoming video call\" : \"Incoming call\"}</span>\n </div>\n <div className=\"mx-meet__ringing-actions\">\n <ControlButton label=\"Decline\" danger onClick={() => void calls.decline(invite)}>\n <PhoneOffIcon />\n </ControlButton>\n {invite.mode === \"video\" ? (\n <ControlButton\n label=\"Accept without video\"\n onClick={() => void calls.accept({ ...invite, mode: \"audio\" })}\n >\n <CameraOffIcon />\n </ControlButton>\n ) : null}\n <ControlButton label=\"Accept\" onClick={() => void calls.accept(invite)}>\n <PhoneIcon />\n </ControlButton>\n </div>\n </section>\n );\n}\n\n/* ------------------------------------------------------------- scheduling */\n\nexport function ScheduleMeeting(props: {\n /** Where meeting links point. `meetingLink` is the ONE link shape. */\n appBaseUrl: string;\n onScheduled?: (slug: string) => void;\n}): ReactNode {\n // THE GUARD, not a throw. See <InertNotice>.\n const host = useMeetHost();\n if (host === null) return <InertNotice what=\"Scheduling a meeting\" />;\n return <ScheduleMeetingBody {...props} host={host} />;\n}\n\nfunction ScheduleMeetingBody({\n appBaseUrl,\n onScheduled,\n host,\n}: {\n appBaseUrl: string;\n onScheduled?: (slug: string) => void;\n host: MeetHost;\n}): ReactNode {\n const [title, setTitle] = useState(\"\");\n const [when, setWhen] = useState(\"\");\n const [kind, setKind] = useState<MeetingKind>(\"scheduled\");\n const [busy, setBusy] = useState(false);\n const [link, setLink] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const disabled = useMemo(() => title.trim().length === 0 || busy, [title, busy]);\n\n return (\n <form\n className=\"mx-meet__schedule\"\n onSubmit={(event) => {\n event.preventDefault();\n if (host.identity.userId === null) return;\n setBusy(true);\n setError(null);\n void host.repository\n .getOrCreateMeeting({\n organizationId: host.identity.organizationId,\n hostUserId: host.identity.userId,\n title: title.trim(),\n kind,\n scheduledFor: when.length > 0 ? new Date(when).toISOString() : null,\n })\n .then((meeting) => {\n setLink(meetingLink(appBaseUrl, meeting.slug));\n onScheduled?.(meeting.slug);\n })\n .catch((thrown: unknown) => {\n setError(\n (thrown as { remedy?: string }).remedy ??\n (thrown as Error).message ??\n \"The meeting could not be created.\",\n );\n })\n .finally(() => setBusy(false));\n }}\n >\n <label className=\"mx-meet__field\">\n <span className=\"mx-meet__field-label\">Title</span>\n <input\n className=\"mx-meet__input\"\n value={title}\n onChange={(event) => setTitle(event.target.value)}\n placeholder=\"Weekly sync\"\n />\n </label>\n\n <label className=\"mx-meet__field\">\n <span className=\"mx-meet__field-label\">When</span>\n <input\n className=\"mx-meet__input\"\n type=\"datetime-local\"\n value={when}\n onChange={(event) => setWhen(event.target.value)}\n />\n </label>\n\n <label className=\"mx-meet__field\">\n <span className=\"mx-meet__field-label\">Repeats</span>\n <select\n className=\"mx-meet__select\"\n value={kind}\n onChange={(event) => setKind(event.target.value as MeetingKind)}\n >\n <option value=\"scheduled\">Once</option>\n <option value=\"recurring\">Recurring — one link, every time</option>\n </select>\n </label>\n\n <button type=\"submit\" className=\"mx-meet__primary\" disabled={disabled}>\n {busy ? \"Creating…\" : \"Create meeting\"}\n </button>\n\n {link !== null ? (\n <p className=\"mx-meet__link-out\">\n <span>Anyone with this link can join — no account needed.</span>\n <code>{link}</code>\n </p>\n ) : null}\n {error !== null ? <p className=\"mx-meet__error\">{error}</p> : null}\n </form>\n );\n}\n\n/** Reactions floating over the stage. Expired by the store, not by hope. */\nexport function ReactionOverlay({\n reactions,\n}: {\n reactions: readonly { id: string; emoji: string }[];\n}): ReactNode {\n if (reactions.length === 0) return null;\n return (\n <div className=\"mx-meet__reactions\" aria-hidden=\"true\">\n {reactions.map((reaction) => (\n <span key={reaction.id} className=\"mx-meet__reaction\">\n {reaction.emoji}\n </span>\n ))}\n </div>\n );\n}\n\nexport type { ParticipantIdentity };\n\n/* ------------------------------------------------------ the meeting record */\n\n/**\n * THE MEETING, AFTER THE MEETING (MRI-D2).\n *\n * 🚨 THE DEFECT THIS REPLACES. A meeting produced a wrap-up summary, decisions,\n * owner-assigned action items, live-note windows, a speaker-attributed\n * transcript and a recording — and then `/meet/<slug>` rendered `<PreJoin>`,\n * offering to join a room that no longer existed. Everything the campaign built\n * after the room closed was reachable only from SQL. A durable link that\n * outlives the meeting (R3) has to resolve to the RECORD.\n *\n * The bar it is written to (PLAN §3, Fireflies/Otter recon): what was decided,\n * who owns what, what was said and by whom, and a question box over all of it.\n *\n * Nothing on this screen is computed in the browser. Every line is a durable\n * row; the answer is streamed from `/intelligence/ask`, which reads those same\n * rows server-side. A part the reader is not allowed to see says so IN WORDS —\n * an empty section is indistinguishable from a meeting where nothing happened.\n */\n\n/**\n * WHAT GUESTS MAY READ OF THIS MEETING — the host's control (MRF-1).\n *\n * 🚨 **HOST-ONLY, AND ABSENT FOR EVERYONE ELSE.** Not greyed out, not present\n * with a tooltip: a participant has no control here at all, because a control\n * that exists only to be refused is the dead-end class this package does not\n * ship (D11-style honesty, same posture as `PersonHostActions`).\n *\n * It is the third rung of the ladder Arman ruled on 2026-09-12 — the system's\n * default, the organization's setting, and this meeting's. \"Use my\n * organization's setting\" is shown WITH what that resolves to, because a label\n * that does not say what the organization chose makes the host guess about\n * other people's words.\n */\nexport function GuestRecordAccessControl({\n meeting,\n}: {\n meeting: MeetingRecord;\n}): ReactNode {\n const host = useMeetHost();\n const inRoomHost = useIsHost();\n const access = useGuestRecordAccess(meeting);\n const viewerId = host?.identity.userId ?? null;\n // The named host of the row, or a host of the room this tick. A co-host who\n // holds only an `iam` grant and is not in the room does not see the control;\n // the server would allow them, so this is the narrow side on purpose — a\n // missing control is honest, a control that lies about who may click it is not.\n const isHost = inRoomHost || (viewerId !== null && meeting.hostUserId === viewerId);\n if (host === null || !isHost) return null;\n\n const resolved =\n access.setting === \"default\" && access.effective !== null\n ? ` Right now that means: ${guestRecordAccessLabel(access.effective.level).toLowerCase()}.`\n : \"\";\n\n return (\n <section className=\"mx-meet__record-section\" aria-label=\"What guests may read\">\n <h2 className=\"mx-meet__record-section-title\">What guests may read</h2>\n <label className=\"mx-meet__field\">\n <span className=\"mx-meet__field-label\">\n People who attended by link, without an account\n </span>\n <select\n className=\"mx-meet__select\"\n value={access.setting}\n disabled={access.saving}\n onChange={(event) => {\n void access.choose(\n event.target.value as (typeof GUEST_RECORD_ACCESS_CHOICES)[number],\n );\n }}\n >\n {GUEST_RECORD_ACCESS_CHOICES.map((choice) => (\n <option key={choice} value={choice}>\n {guestRecordAccessLabel(choice)}\n </option>\n ))}\n </select>\n </label>\n <p className=\"mx-meet__panel-note\">\n {guestRecordAccessExplanation(access.setting)}\n {resolved}\n </p>\n {access.saving ? (\n <p className=\"mx-meet__panel-note\" role=\"status\">\n Saving what guests may read…\n </p>\n ) : null}\n {access.error !== null ? (\n <ErrorBox as=\"div\" className=\"mx-meet__refusal\" error={access.error} operation=\"Change who can join\" origin=\"meet/components\">\n <p className=\"mx-meet__refusal-reason\">{access.error.message}</p>\n <p className=\"mx-meet__refusal-remedy\">{access.error.remedy}</p>\n </ErrorBox>\n ) : null}\n </section>\n );\n}\n\nexport function MeetingRecordView({\n meeting,\n onRejoin,\n}: {\n meeting: MeetingRecord;\n /** Optional: a recurring link can be re-opened. Absent for a one-off. */\n onRejoin?: () => void;\n}): ReactNode {\n const host = useMeetHost();\n if (host === null) {\n return (\n <div className=\"mx-meet mx-meet--record\">\n <InertNotice what=\"This meeting record\" />\n </div>\n );\n }\n return <MeetingRecordBody meeting={meeting} {...(onRejoin !== undefined ? { onRejoin } : {})} />;\n}\n\nfunction MeetingRecordBody({\n meeting,\n onRejoin,\n}: {\n meeting: MeetingRecord;\n onRejoin?: () => void;\n}): ReactNode {\n const host = useRequiredMeetHost();\n const record = useMeetingRecord(meeting);\n const [question, setQuestion] = useState(\"\");\n const [tab, setTab] = useState<\"summary\" | \"notes\" | \"transcript\">(\"summary\");\n\n if (record.failure !== null) {\n return (\n <div className=\"mx-meet mx-meet--record\">\n <ErrorBox as=\"div\" className=\"mx-meet__empty\" error={record.failure} operation=\"Open this meeting record\" origin=\"meet/components\">\n <p className=\"mx-meet__empty-title\">This meeting record could not be opened</p>\n <p className=\"mx-meet__empty-body\">{record.failure.message}</p>\n <p className=\"mx-meet__empty-body\">{record.failure.remedy}</p>\n </ErrorBox>\n </div>\n );\n }\n\n if (record.loading || record.record === null) {\n return (\n <div className=\"mx-meet mx-meet--record\">\n <div className=\"mx-meet__empty\" role=\"status\">\n <p className=\"mx-meet__empty-title\">Opening the meeting record…</p>\n <p className=\"mx-meet__empty-body\">\n Reading the summary, the notes and the transcript this meeting left behind.\n </p>\n </div>\n </div>\n );\n }\n\n const bundle = record.record;\n const wrapUp = wrapUpStatus(bundle);\n const blocks = groupTranscript(bundle.transcript, bundle.names);\n const notice = recordingNotice(bundle.recording);\n const fileId = playableRecordingFileId(bundle.recording);\n // One entry per PERSON — a rejoin or a second device is not a second attendee.\n const attended = uniqueAttendees(\n bundle.attendees.filter((person) => person.admissionState !== \"denied\"),\n bundle.names,\n );\n const restrictionNotices = summarizeMeetingRecordRestrictions(bundle.restrictions);\n // The server permits the room-pass Q&A only while a guest is in a live\n // meeting. Do not offer a finished-record action that its authorization\n // boundary will always refuse; signed-in members retain durable Q&A.\n const guestFinishedMeeting = host.identity.userId === null && meeting.endedAt !== null;\n const everyRecordPartRefused = (['attendance', 'notes', 'transcript', 'recording'] as const).every(\n (part) => wasRefused(bundle, part),\n );\n const entirelyRestricted =\n everyRecordPartRefused &&\n bundle.attendees.length === 0 &&\n bundle.liveNotes.length === 0 &&\n bundle.transcript.length === 0 &&\n bundle.recording === null &&\n bundle.summary === null &&\n bundle.decisions.length === 0 &&\n bundle.actionItems.length === 0;\n\n if (entirelyRestricted) {\n return (\n <div className=\"mx-meet mx-meet--record\">\n <header className=\"mx-meet__record-head\">\n <div className=\"mx-meet__record-head-inner\">\n <p className=\"mx-meet__record-eyebrow\">Meeting record</p>\n <h1 className=\"mx-meet__record-title\">{meeting.title}</h1>\n <p className=\"mx-meet__record-when\">{meetingWhen(meeting)}</p>\n {onRejoin !== undefined ? (\n <button type=\"button\" className=\"mx-meet__link\" onClick={onRejoin}>\n Open this link again\n </button>\n ) : null}\n </div>\n </header>\n <div className=\"mx-meet__record-body\">\n {restrictionNotices.map((notice) => (\n <div key={notice.parts.join('-')} className=\"mx-meet__record-access\" role=\"status\">\n <p className=\"mx-meet__record-access-title\">About this record</p>\n <p className=\"mx-meet__record-access-message\">{notice.message}</p>\n <p className=\"mx-meet__record-access-remedy\">{notice.remedy}</p>\n </div>\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"mx-meet mx-meet--record\">\n <header className=\"mx-meet__record-head\">\n <div className=\"mx-meet__record-head-inner\">\n <p className=\"mx-meet__record-eyebrow\">Meeting record</p>\n <h1 className=\"mx-meet__record-title\">{meeting.title}</h1>\n <p className=\"mx-meet__record-when\">{meetingWhen(meeting)}</p>\n {onRejoin !== undefined ? (\n <button type=\"button\" className=\"mx-meet__link\" onClick={onRejoin}>\n Open this link again\n </button>\n ) : null}\n </div>\n </header>\n\n <div className=\"mx-meet__record-body\">\n {/* WHAT THIS READER CANNOT SEE, AND WHY. Never an empty section. */}\n {restrictionNotices.map((notice) => (\n <div key={notice.parts.join(\"-\")} className=\"mx-meet__record-access\" role=\"status\">\n <p className=\"mx-meet__record-access-title\">About this record</p>\n <p className=\"mx-meet__record-access-message\">{notice.message}</p>\n <p className=\"mx-meet__record-access-remedy\">{notice.remedy}</p>\n </div>\n ))}\n\n {/* WHO WAS THERE — the durable attendance rows, which outlive the room. */}\n {attended.length === 0 ? (\n /* NOT SILENCE. A refused attendance read used to remove the whole\n section, so the reader could not tell \"nobody\" from \"not shown\". */\n <section className=\"mx-meet__record-section\" aria-label=\"Who attended\">\n <h2 className=\"mx-meet__record-section-title\">Who attended</h2>\n <p className=\"mx-meet__panel-note\">\n {absenceSentence(bundle, \"attendance\", \"Nobody is recorded as having attended.\")}\n </p>\n </section>\n ) : (\n <section className=\"mx-meet__record-section\" aria-label=\"Who attended\">\n <h2 className=\"mx-meet__record-section-title\">Who attended</h2>\n <ul className=\"mx-meet__record-attendees\">\n {attended.map((person) => (\n <li key={person.id} className=\"mx-meet__record-attendee\">\n <Avatar\n name={displayNameFor(bundle.names, person.identity, person.displayName)}\n url={person.avatarUrl}\n size={28}\n />\n <span className=\"mx-meet__person-name\">\n {displayNameFor(bundle.names, person.identity, person.displayName)}\n {person.role === \"host\" ? <span className=\"mx-meet__badge\">Host</span> : null}\n {person.role === \"guest\" ? <span className=\"mx-meet__badge\">Guest</span> : null}\n {/* Attendance establishes an agent's role, not whether it\n captured a transcript. Recording-only meetings can have\n an agent row without any live capture. */}\n {person.isAgent ? (\n <span className=\"mx-meet__badge\">Meeting assistant</span>\n ) : null}\n </span>\n </li>\n ))}\n </ul>\n </section>\n )}\n\n {/* THE RECORDING. `available` plays; anything else states what it is\n doing. There is never a player over a file that does not exist. */}\n {bundle.recording !== null ? (\n <section className=\"mx-meet__record-section mx-meet__recording-card\" aria-label=\"Recording\">\n <h2 className=\"mx-meet__record-section-title\">Recording</h2>\n {fileId !== null ? (\n <>\n <RecordingPlayer fileId={fileId} />\n {notice !== null ? <p className=\"mx-meet__panel-note\">{notice}</p> : null}\n </>\n ) : (\n <p className=\"mx-meet__panel-note\">{notice ?? \"This recording has no file.\"}</p>\n )}\n </section>\n ) : wasRefused(bundle, \"recording\") ? (\n <section className=\"mx-meet__record-section\" aria-label=\"Recording\">\n <h2 className=\"mx-meet__record-section-title\">Recording</h2>\n <p className=\"mx-meet__panel-note\">{REFUSED_ABSENCE}</p>\n </section>\n ) : null}\n\n <nav className=\"mx-meet__record-tabs\" aria-label=\"Meeting record sections\">\n <button\n type=\"button\"\n className={`mx-meet__record-tab${tab === \"summary\" ? \" mx-meet__record-tab--active\" : \"\"}`}\n onClick={() => setTab(\"summary\")}\n aria-pressed={tab === \"summary\"}\n >\n Summary & decisions\n </button>\n <button\n type=\"button\"\n className={`mx-meet__record-tab${tab === \"notes\" ? \" mx-meet__record-tab--active\" : \"\"}`}\n onClick={() => setTab(\"notes\")}\n aria-pressed={tab === \"notes\"}\n >\n Notes as it happened\n </button>\n <button\n type=\"button\"\n className={`mx-meet__record-tab${tab === \"transcript\" ? \" mx-meet__record-tab--active\" : \"\"}`}\n onClick={() => setTab(\"transcript\")}\n aria-pressed={tab === \"transcript\"}\n >\n Transcript\n </button>\n </nav>\n\n {tab === \"summary\" ? (\n <>\n <section className=\"mx-meet__record-section\" aria-label=\"Summary\">\n <h2 className=\"mx-meet__record-section-title\">Summary</h2>\n {/* 🚨 NEVER AN ABSENCE THIS READER CANNOT KNOW (MRI-A16), AND\n NEVER AN ABSENCE THAT IS MERELY EARLY (MRI-A18). This said\n \"No wrap-up was written for this meeting\" under a panel that\n had just refused to read the notes (MRI-C8), and again for the\n ~33 s a perfectly healthy wrap-up job takes to land. Which of\n the five it is comes from `wrapUpStatus`, never from here. */}\n {wrapUp.state === \"written\" ? (\n <p className=\"mx-meet__record-summary\">{bundle.summary?.text}</p>\n ) : wrapUp.state === \"in-progress\" ? (\n <div className=\"mx-meet__panel-note\" role=\"status\">\n <p>{wrapUp.message}</p>\n {/* A LIVE AFFORDANCE, not a spinner over a promise. The\n record view has no realtime feed for a meeting whose room\n is already deleted, so the honest control is the one that\n re-reads the record. */}\n <button type=\"button\" className=\"mx-meet__link\" onClick={record.reload}>\n Check again\n </button>\n </div>\n ) : (\n <p className=\"mx-meet__panel-note\" role={wrapUp.state === \"failed\" ? \"alert\" : undefined}>\n {wrapUp.message}\n </p>\n )}\n </section>\n <NoteList\n title=\"Decisions\"\n notes={bundle.decisions}\n empty={absenceSentence(\n bundle,\n \"notes\",\n \"Nothing was recorded as a decision in this meeting.\",\n )}\n />\n <NoteList\n title=\"Action items\"\n notes={bundle.actionItems}\n empty={absenceSentence(\n bundle,\n \"notes\",\n \"No action items came out of this meeting.\",\n )}\n />\n </>\n ) : null}\n\n {tab === \"notes\" ? (\n <section className=\"mx-meet__record-section\" aria-label=\"Notes as it happened\">\n <h2 className=\"mx-meet__record-section-title\">Notes as it happened</h2>\n {bundle.liveNotes.length === 0 ? (\n <p className=\"mx-meet__panel-note\">\n {absenceSentence(\n bundle,\n \"notes\",\n \"No live notes are available for this meeting.\",\n )}\n </p>\n ) : (\n <ul className=\"mx-meet__notes\">\n {bundle.liveNotes.map((note) => (\n <li key={note.id} className=\"mx-meet__note\">\n {note.window !== null ? (\n <span className=\"mx-meet__badge\">Window {note.window}</span>\n ) : null}\n {note.text}\n </li>\n ))}\n </ul>\n )}\n </section>\n ) : null}\n\n {tab === \"transcript\" ? (\n <section className=\"mx-meet__record-section\" aria-label=\"Transcript\">\n <h2 className=\"mx-meet__record-section-title\">\n Transcript\n <span className=\"mx-meet__record-count\">\n {bundle.transcript.length === 1\n ? \"1 line\"\n : `${bundle.transcript.length} lines`}\n </span>\n </h2>\n {blocks.length === 0 ? (\n <p className=\"mx-meet__panel-note\">\n {absenceSentence(\n bundle,\n \"transcript\",\n \"No transcript is available for this meeting.\",\n )}\n </p>\n ) : (\n <ol className=\"mx-meet__record-transcript\">\n {blocks.map((block) => (\n <li key={block.id} className=\"mx-meet__record-block\">\n <p className=\"mx-meet__record-speaker\">\n {block.speaker}\n <time className=\"mx-meet__record-time\" dateTime={block.startedAt}>\n {clockOf(block.startedAt)}\n </time>\n </p>\n {block.lines.map((line) => (\n <p key={line.id} className=\"mx-meet__record-line\">\n {line.text}\n </p>\n ))}\n </li>\n ))}\n </ol>\n )}\n </section>\n ) : null}\n\n {/* WHAT GUESTS MAY READ, decided where the host can see what there is\n to share. Absent entirely for anyone who is not a host (MRF-1). */}\n <GuestRecordAccessControl meeting={meeting} />\n\n {/* Signed-in members can ask about durable rows after the room closes.\n A guest's room pass deliberately expires for Q&A when the meeting\n ends, even if that guest may still read the shared record. */}\n <section className=\"mx-meet__record-section\" aria-label=\"Ask about this meeting\">\n <h2 className=\"mx-meet__record-section-title\">Ask about this meeting</h2>\n {guestFinishedMeeting ? (\n <p className=\"mx-meet__panel-note\">\n Sign in to ask the assistant about a meeting after it ends.\n </p>\n ) : (\n <>\n <form\n className=\"mx-meet__composer\"\n onSubmit={(event) => {\n event.preventDefault();\n const trimmed = question.trim();\n if (trimmed.length === 0) return;\n void record.ask(trimmed);\n }}\n >\n <input\n className=\"mx-meet__input\"\n value={question}\n onChange={(event) => setQuestion(event.target.value)}\n placeholder=\"What did we decide about the vendor quote?\"\n aria-label=\"Ask about this meeting\"\n />\n <button\n type=\"submit\"\n className=\"mx-meet__primary\"\n disabled={question.trim().length === 0 || record.asking}\n >\n {record.asking ? \"Asking…\" : \"Ask\"}\n </button>\n </form>\n {record.answer !== null ? (\n <p className=\"mx-meet__answer\">{record.answer}</p>\n ) : null}\n {record.coverage !== null ? (\n <p className=\"mx-meet__coverage\">\n Answered from {record.coverage.segmentsUsed} of {record.coverage.segmentsTotal}{\" \"}\n transcript {record.coverage.segmentsTotal === 1 ? \"line\" : \"lines\"}\n {record.coverage.truncated ? \" (the oldest were left out)\" : \"\"}.\n </p>\n ) : null}\n {record.askError !== null ? (\n <ErrorBox as=\"div\" className=\"mx-meet__refusal\" error={record.askError} operation=\"Ask about this meeting\" origin=\"meet/components\">\n <p className=\"mx-meet__refusal-reason\">{record.askError.message}</p>\n <p className=\"mx-meet__refusal-remedy\">{record.askError.remedy}</p>\n </ErrorBox>\n ) : null}\n </>\n )}\n </section>\n </div>\n </div>\n );\n}\n\n/**\n * THE RECORDING, PLAYED THROUGH THE PLATFORM FILE ID (R3).\n *\n * `meet_recordings.file_id` is a PLATFORM file id, never a provider URL — a\n * LiveKit URL is orphaned the day the room is garbage collected, which is the\n * whole reason the column is not `url`. aidream serves the bytes at\n * `GET /files/{id}/download`, and that route is AUTHENTICATED: nothing in this\n * platform ever returns a signed URL (the files law, 2026-08-21/26).\n *\n * 🚨 A BEARER TOKEN IS NOT ENOUGH, and believing it was is what broke this\n * screen. Through 0.4.7 this component built its own `fetch` with only an\n * `authorization` header, so aidream's org-admission middleware answered 400\n * `organization_required` and a 1.38 MB recording that had landed perfectly\n * could not be played by the host who made it (MRI-C8). Every request the\n * package makes now goes through `host.api` (`core/api.ts`), which carries the\n * organization on all of them and cannot be bypassed — `core/api.test.ts`\n * fails the build if a second way to reach aidream appears.\n *\n * It is fetched on a click, never on render: a meeting recording is tens of\n * megabytes and nobody who opened the summary asked to download a video.\n * Every state here is a sentence — loading, failed with a remedy, or playing.\n */\n/** Said after a streaming media error, before a byte retry is attempted. */\nconst STREAM_REFUSED =\n \"Streaming playback did not start, so this recording was downloaded in full instead. \" +\n \"Downloading can take longer, and seeking is unavailable until it finishes.\";\n\nconst PLAYBACK_RETRY_REMEDY =\n \"Reload the page and try again. If it still will not play, ask a meeting host to check the recording.\";\n\nexport function RecordingPlayer(props: { fileId: string }): ReactNode {\n // THE GUARD, not a throw (rule 7c). `<RecordingPlayer>` is a PUBLIC entry\n // component, so a consumer may render it while the provider is still inert —\n // which, since 0.6.0, includes the tick the session read takes (DD-240). It\n // used to call `useRequiredMeetHost()` and throw a package error into the\n // consumer's tree for that tick.\n const host = useMeetHost();\n if (host === null) return <InertNotice what=\"This recording\" />;\n return <RecordingPlayerBody {...props} host={host} />;\n}\n\nfunction RecordingPlayerBody({ fileId, host }: { fileId: string; host: MeetHost }): ReactNode {\n const [media, setMedia] = useState<MeetFileMedia | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<{ message: string; remedy: string } | null>(null);\n\n // A `blob:` url is revoked when this unmounts; a streaming url is not one and\n // must not be revoked. Leaking a blob pins the whole video for the tab's life.\n useEffect(() => {\n if (media === null || media.kind !== \"bytes\") return undefined;\n const url = media.url;\n return () => URL.revokeObjectURL(url);\n }, [media]);\n\n if (media !== null) {\n return (\n <div className=\"mx-meet__record-section\">\n {/* eslint-disable-next-line jsx-a11y/media-has-caption -- the transcript\n below IS the caption track, and it is on the same screen. */}\n <video\n className=\"mx-meet__record-player\"\n src={media.url}\n controls\n preload=\"metadata\"\n onError={() => {\n if (media.kind === \"bytes\") {\n setMedia(null);\n setError({\n message: \"The downloaded recording could not be played.\",\n remedy: PLAYBACK_RETRY_REMEDY,\n });\n return;\n }\n // The media element does not classify codec, network, and browser\n // session failures. Retry authorized bytes without guessing why.\n if (loading) return;\n setLoading(true);\n void (async () => {\n try {\n setMedia({\n url: await host.api.fetchObjectUrl({\n path: fileDownloadPath(fileId),\n operation: \"meet.recording.play\",\n }),\n kind: \"bytes\",\n fallbackReason: STREAM_REFUSED,\n });\n } catch (thrown) {\n const failure = thrown as { message?: string; remedy?: string };\n setMedia(null);\n setError({\n message: failure.message ?? \"The recording could not be played.\",\n remedy: failure.remedy ?? PLAYBACK_RETRY_REMEDY,\n });\n } finally {\n setLoading(false);\n }\n })();\n }}\n />\n {/* 🚨 THE FALLBACK ANNOUNCES ITSELF. When the file had to be downloaded\n in full before playing, the person who waited deserves to know why. */}\n {media.fallbackReason !== null ? (\n <p className=\"mx-meet__panel-note\">{media.fallbackReason}</p>\n ) : null}\n </div>\n );\n }\n\n return (\n <div className=\"mx-meet__record-section\">\n {error !== null ? (\n <ErrorBox as=\"div\" className=\"mx-meet__refusal\" error={error} operation=\"Complete this meeting action\" origin=\"meet/components\">\n <p className=\"mx-meet__refusal-reason\">{error.message}</p>\n <p className=\"mx-meet__refusal-remedy\">{error.remedy}</p>\n </ErrorBox>\n ) : null}\n <button\n type=\"button\"\n className=\"mx-meet__primary mx-meet__record-play\"\n disabled={loading}\n onClick={() => {\n setLoading(true);\n setError(null);\n void (async () => {\n try {\n // 🚨 THROUGH THE ONE CLIENT (MRI-A16). This call used to be a\n // bare `fetch` carrying only a bearer token, and aidream answered\n // 400 `organization_required` — a perfectly landed recording that\n // the host who made it could not play (MRI-C8).\n setMedia(await host.api.fileMedia(fileId, \"meet.recording.play\"));\n } catch (thrown) {\n const failure = thrown as { message?: string; remedy?: string };\n setError({\n message: failure.message ?? \"The recording could not be loaded.\",\n remedy: failure.remedy ?? PLAYBACK_RETRY_REMEDY,\n });\n } finally {\n setLoading(false);\n }\n })();\n }}\n >\n {loading ? \"Loading the recording…\" : \"Play the recording\"}\n </button>\n </div>\n );\n}\n\n/** `10:35` — the clock a person reads beside a line of transcript. */\nfunction clockOf(iso: string): string {\n const at = new Date(iso);\n if (Number.isNaN(at.getTime())) return \"\";\n return at.toLocaleTimeString(undefined, { hour: \"numeric\", minute: \"2-digit\" });\n}\n\n/**\n * THE MEETINGS LIST — live meetings AND the records of finished ones (MRI-D2).\n *\n * A finished meeting is not gone: it is the summary, the decisions, the action\n * items and the transcript behind the same durable link (R3). A list that\n * silently dropped ended meetings is what made every wrap-up unreachable from\n * the product, so an ended row is a first-class row here and its action says\n * what it opens.\n */\nexport function MeetingList({ baseUrl }: { baseUrl?: string }): ReactNode {\n const host = useMeetHost();\n const list = useMeetings();\n if (host === null) return <InertNotice what=\"Your meetings\" />;\n\n if (list.failure !== null) {\n return (\n <ErrorBox as=\"div\" className=\"mx-meet__empty\" error={list.failure} operation=\"List your meetings\" origin=\"meet/components\">\n <p className=\"mx-meet__empty-title\">Your meetings could not be listed</p>\n <p className=\"mx-meet__empty-body\">{list.failure.message}</p>\n <p className=\"mx-meet__empty-body\">{list.failure.remedy}</p>\n </ErrorBox>\n );\n }\n\n if (list.loading) {\n return (\n <div className=\"mx-meet__empty\" role=\"status\">\n <p className=\"mx-meet__empty-title\">Loading your meetings…</p>\n </div>\n );\n }\n\n if (list.meetings.length === 0) {\n return (\n <div className=\"mx-meet__empty\" role=\"status\">\n <p className=\"mx-meet__empty-title\">No meetings yet</p>\n <p className=\"mx-meet__empty-body\">\n Create one above. Its link works before, during and after the meeting — afterwards it\n opens the record.\n </p>\n </div>\n );\n }\n\n const origin =\n baseUrl ?? (typeof window === \"undefined\" ? \"\" : window.location.origin);\n\n return (\n <ul className=\"mx-meet-list\">\n {list.meetings.map((meeting) => {\n const ended = meeting.endedAt !== null;\n return (\n <li key={meeting.id} className=\"mx-meet-list__row\">\n <div className=\"mx-meet-list__main\">\n <span className=\"mx-meet-list__title\">\n {meeting.title}\n {ended ? <span className=\"mx-meet__badge\">Ended</span> : null}\n </span>\n <span className=\"mx-meet-list__when\">{meetingWhen(meeting)}</span>\n </div>\n <a className=\"mx-meet-list__action\" href={meetingLink(origin, meeting.slug)}>\n {ended ? \"Open the record\" : \"Join\"}\n </a>\n </li>\n );\n })}\n </ul>\n );\n}\n","/**\n * AFTER THE MEETING (Meet wave 3) — the pure pieces every client needs once the\n * room is gone: the attendance report, the transcript and notes as documents,\n * a moment in the transcript as a moment in the recording, search within one\n * transcript, and the two server calls behind the recap email and the saved\n * chat.\n *\n * Nothing here computes MEANING (same rule as `record.ts`): the summary,\n * decisions and action items are the wrap-up's durable rows; this file only\n * arranges, measures and formats them. Every function is framework-free so a\n * worker, a test and a browser produce byte-identical exports.\n */\n\nimport { formatDurationMs } from \"@ai-matrx/kit/format\";\nimport { readServerRefusal, refusalFromResponse } from \"./ai\";\nimport type { MeetApi } from \"./api\";\nimport { MeetError } from \"./errors\";\nimport { displayNameFor, type NameBook } from \"./names\";\nimport type { MeetingRecordBundle } from \"./record\";\nimport { chatFromRow } from \"./room-events\";\nimport type { RoomChatMessage } from \"./store\";\nimport { MEET_ROUTES, meetingPath, ROOM_TOKEN_HEADER } from \"./tokens\";\nimport type {\n MeetingAttendee,\n MeetingId,\n MeetingNote,\n MeetingRecord,\n RecordingRecord,\n TranscriptSegment,\n} from \"./types\";\n\n/* ─────────────────────────── Attendance ─────────────────────────── */\n\n/**\n * Who someone was, in the words an attendance report uses. `signed-in guest` is\n * an account from outside the meeting's organization that followed the link;\n * `guest` has no account at all.\n */\nexport type AttendanceKind = \"host\" | \"cohost\" | \"member\" | \"signed-in guest\" | \"guest\" | \"assistant\";\n\nexport interface AttendanceRow {\n readonly id: string;\n readonly identity: string;\n readonly name: string;\n readonly userId: string | null;\n readonly kind: AttendanceKind;\n /** First time they were in the room; null when they knocked and never came in. */\n readonly joinedAt: string | null;\n /** When they left; null while still in the room or when the leave was never recorded. */\n readonly leftAt: string | null;\n /**\n * Time in the room. A missing `leftAt` is measured to the meeting's end —\n * the room closed around them — and `null` only when neither is known.\n */\n readonly durationMs: number | null;\n /** True when `durationMs` was measured to the meeting's end, not a recorded leave. */\n readonly durationToEnd: boolean;\n readonly admission: MeetingAttendee[\"admissionState\"];\n /** How many times this person came in (a rejoin or a second device). */\n readonly joins: number;\n}\n\nfunction kindOf(person: MeetingAttendee): AttendanceKind {\n if (person.isAgent) return \"assistant\";\n if (person.role === \"host\") return \"host\";\n if (person.role === \"cohost\") return \"cohost\";\n if (person.role === \"guest\") return person.userId !== null ? \"signed-in guest\" : \"guest\";\n return \"member\";\n}\n\nfunction ms(iso: string | null): number | null {\n if (iso === null) return null;\n const at = new Date(iso).getTime();\n return Number.isNaN(at) ? null : at;\n}\n\n/**\n * The attendance report of ONE meeting, host first then by arrival. People who\n * knocked and were never let in are kept (with no join time) — \"who asked to\n * come in\" is part of the record — but a denied knock has no duration.\n */\n/**\n * WHO a participant row is, as a PERSON (verifier, 2026-09-27: an export listed\n * the same attendee twice under \"attended\"). A signed-in person is their\n * account — every device and every rejoin is one person. A guest without an\n * account gets a fresh `guest:<random>` identity on every join, so the name\n * they typed is the only thread between their joins (Zoom's attendee report\n * merges link guests the same way); two different accountless guests who\n * typed the identical name read as one, which is the lesser error.\n */\nexport function attendeeKey(person: MeetingAttendee, names: NameBook = {}): string {\n if (person.userId !== null) return `user:${person.userId}`;\n if (person.isAgent) return `agent:${person.identity}`;\n const name = displayNameFor(names, person.identity, person.displayName).trim().toLowerCase();\n return name.length > 0 ? `guest-name:${name}` : `identity:${person.identity}`;\n}\n\n/**\n * One row per PERSON, in first-seen order: the row that actually joined (the\n * earliest) represents them. For a list of names or a head-count; the\n * attendance REPORT merges times as well (`attendanceReport`).\n */\nexport function uniqueAttendees(\n attendees: readonly MeetingAttendee[],\n names: NameBook = {},\n): readonly MeetingAttendee[] {\n const byKey = new Map<string, MeetingAttendee>();\n for (const person of attendees) {\n const key = attendeeKey(person, names);\n const kept = byKey.get(key);\n if (kept === undefined) {\n byKey.set(key, person);\n continue;\n }\n const keptJoin = ms(kept.joinedAt);\n const join = ms(person.joinedAt);\n if (join !== null && (keptJoin === null || join < keptJoin)) byKey.set(key, person);\n }\n return [...byKey.values()];\n}\n\nconst KIND_RANK: Record<AttendanceKind, number> = {\n host: 0,\n cohost: 1,\n member: 2,\n \"signed-in guest\": 3,\n guest: 4,\n assistant: 5,\n};\n\n/** Total time covered by a set of [start, end] intervals — overlaps count once. */\nfunction coveredMs(intervals: readonly (readonly [number, number])[]): number {\n const sorted = [...intervals].sort((a, b) => a[0] - b[0]);\n let total = 0;\n let from = -Infinity;\n let to = -Infinity;\n for (const [start, end] of sorted) {\n if (start > to) {\n if (to > from) total += to - from;\n from = start;\n to = end;\n } else if (end > to) {\n to = end;\n }\n }\n if (to > from) total += to - from;\n return total;\n}\n\nexport function attendanceReport(\n meeting: MeetingRecord,\n attendees: readonly MeetingAttendee[],\n names: NameBook = {},\n): readonly AttendanceRow[] {\n const end = ms(meeting.endedAt);\n const perJoin = attendees.map((person): AttendanceRow => {\n const joined = ms(person.joinedAt);\n const left = ms(person.leftAt);\n const until = left ?? end;\n const duration = joined !== null && until !== null && until >= joined ? until - joined : null;\n return {\n id: person.id,\n identity: person.identity,\n name: displayNameFor(names, person.identity, person.displayName),\n userId: person.userId,\n kind: kindOf(person),\n joinedAt: person.joinedAt,\n leftAt: person.leftAt,\n durationMs: duration,\n durationToEnd: duration !== null && left === null,\n admission: person.admissionState,\n joins: 1,\n };\n });\n // ONE ROW PER PERSON: several joins (a rejoin, a second device) are one\n // attendee with their first arrival, last departure and total time — time\n // in the room twice at once counts once.\n const groups = new Map<string, { rows: AttendanceRow[]; people: MeetingAttendee[] }>();\n attendees.forEach((person, index) => {\n const key = attendeeKey(person, names);\n const group = groups.get(key) ?? { rows: [], people: [] };\n group.rows.push(perJoin[index]!);\n group.people.push(person);\n groups.set(key, group);\n });\n const rows = [...groups.values()].map(({ rows: joins }): AttendanceRow => {\n if (joins.length === 1) return joins[0]!;\n const came = joins.filter((row) => row.joinedAt !== null);\n const first =\n [...came].sort((a, b) => (ms(a.joinedAt) ?? 0) - (ms(b.joinedAt) ?? 0))[0] ?? joins[0]!;\n const kind = joins.reduce<AttendanceKind>(\n (best, row) => (KIND_RANK[row.kind] < KIND_RANK[best] ? row.kind : best),\n first.kind,\n );\n const open = came.some((row) => row.leftAt === null);\n const lastLeave = came.reduce<number | null>((latest, row) => {\n const left = ms(row.leftAt);\n return left !== null && (latest === null || left > latest) ? left : latest;\n }, null);\n const intervals = came.flatMap((row): (readonly [number, number])[] => {\n const joined = ms(row.joinedAt);\n return joined !== null && row.durationMs !== null ? [[joined, joined + row.durationMs]] : [];\n });\n return {\n ...first,\n kind,\n leftAt: open ? null : lastLeave === null ? null : new Date(lastLeave).toISOString(),\n durationMs: intervals.length === 0 ? null : coveredMs(intervals),\n durationToEnd: came.some((row) => row.durationToEnd),\n joins: came.length === 0 ? joins.length : came.length,\n };\n });\n const rank = KIND_RANK;\n return rows.sort((a, b) => {\n if (rank[a.kind] !== rank[b.kind]) return rank[a.kind] - rank[b.kind];\n return (ms(a.joinedAt) ?? Number.MAX_SAFE_INTEGER) - (ms(b.joinedAt) ?? Number.MAX_SAFE_INTEGER);\n });\n}\n\n/** Headline numbers for the top of a report. The assistant is never a person. */\nexport function attendanceTotals(rows: readonly AttendanceRow[]): {\n readonly people: number;\n readonly guests: number;\n readonly neverAdmitted: number;\n readonly averageMs: number | null;\n} {\n const humans = rows.filter((row) => row.kind !== \"assistant\");\n const attended = humans.filter((row) => row.joinedAt !== null);\n const timed = attended.filter((row) => row.durationMs !== null);\n return {\n people: attended.length,\n guests: attended.filter((row) => row.kind === \"guest\" || row.kind === \"signed-in guest\").length,\n neverAdmitted: humans.filter((row) => row.joinedAt === null).length,\n averageMs:\n timed.length === 0\n ? null\n : Math.round(timed.reduce((sum, row) => sum + (row.durationMs ?? 0), 0) / timed.length),\n };\n}\n\nfunction csvCell(value: string | number | null): string {\n if (value === null) return \"\";\n const text = String(value);\n return /[\",\\n\\r]/.test(text) ? `\"${text.replace(/\"/g, '\"\"')}\"` : text;\n}\n\nexport const ATTENDANCE_CSV_HEADER = [\n \"Meeting\",\n \"Meeting started\",\n \"Name\",\n \"Attended as\",\n \"Joined\",\n \"Left\",\n \"Minutes in the meeting\",\n \"Admission\",\n] as const;\n\n/**\n * CSV for a spreadsheet: one header row, one row per person, ISO timestamps (a\n * spreadsheet parses them; a formatted local clock loses the zone). Several\n * meetings — a series — concatenate with one header.\n */\nexport function attendanceCsv(\n reports: readonly { meeting: MeetingRecord; rows: readonly AttendanceRow[] }[],\n): string {\n const lines = [ATTENDANCE_CSV_HEADER.join(\",\")];\n for (const { meeting, rows } of reports) {\n for (const row of rows) {\n lines.push(\n [\n meeting.title,\n meeting.startedAt ?? meeting.scheduledFor,\n row.name,\n row.kind,\n row.joinedAt,\n row.leftAt,\n row.durationMs === null ? null : Math.round(row.durationMs / 6_000) / 10,\n row.admission,\n ]\n .map(csvCell)\n .join(\",\"),\n );\n }\n }\n return `${lines.join(\"\\r\\n\")}\\r\\n`;\n}\n\n/* ───────────────────── A moment in the recording ───────────────────── */\n\n/**\n * Where an instant of the meeting falls in the RECORDING, in milliseconds from\n * its start — or `null` when the recording does not cover it (a recording is\n * often a few minutes of a longer meeting). Never a clamp: seeking a line that\n * was said before recording began to 0:00 would play the wrong words.\n */\nexport function recordingOffsetMs(at: string, recording: RecordingRecord | null): number | null {\n if (recording === null || recording.state !== \"available\") return null;\n const start = ms(recording.startedAt);\n const moment = ms(at);\n if (start === null || moment === null || moment < start) return null;\n const end = ms(recording.endedAt);\n if (end !== null && moment > end) return null;\n return moment - start;\n}\n\n/** `m:ss` or `h:mm:ss` — a position in a recording or a meeting. */\nexport function clockPosition(offsetMs: number): string {\n const total = Math.max(0, Math.floor(offsetMs / 1000));\n const h = Math.floor(total / 3600);\n const m = Math.floor((total % 3600) / 60);\n const s = total % 60;\n const ss = String(s).padStart(2, \"0\");\n return h > 0 ? `${h}:${String(m).padStart(2, \"0\")}:${ss}` : `${m}:${ss}`;\n}\n\n/* ───────────────────── Search within one transcript ───────────────────── */\n\nexport interface TranscriptMatch {\n readonly segmentId: string;\n /** [start, end) character ranges inside the segment's text, in order. */\n readonly ranges: readonly (readonly [number, number])[];\n}\n\n/**\n * Case-insensitive search of the transcript text AND the speaker's\n * name. Returns matches in transcript order. An empty query matches nothing.\n */\nexport function searchTranscript(\n segments: readonly TranscriptSegment[],\n query: string,\n names: NameBook = {},\n): readonly TranscriptMatch[] {\n const needle = fold(query.trim());\n if (needle.length === 0) return [];\n const out: TranscriptMatch[] = [];\n for (const segment of segments) {\n const hay = fold(segment.text);\n const ranges: [number, number][] = [];\n let from = 0;\n for (;;) {\n const at = hay.indexOf(needle, from);\n if (at < 0) break;\n ranges.push([at, at + needle.length]);\n from = at + needle.length;\n }\n const speaker = fold(displayNameFor(names, segment.identity, segment.speaker));\n if (ranges.length > 0 || speaker.includes(needle)) {\n out.push({ segmentId: segment.id, ranges });\n }\n }\n return out;\n}\n\n/** Lowercase, strip combining marks; length-preserving for the Latin range. */\nfunction fold(value: string): string {\n return value\n .normalize(\"NFD\")\n .replace(/[̀-ͯ]/g, (mark) => (mark.length === 1 ? \"\" : mark))\n .toLowerCase();\n}\n\n/* ───────────────────────── Documents ───────────────────────── */\n\nexport type TranscriptFormat = \"txt\" | \"md\" | \"vtt\";\n\ninterface ExportOptions {\n readonly names?: NameBook;\n /** Timestamps as a clock of day (default) or offsets from `zero`. */\n readonly locale?: string;\n readonly timeZone?: string;\n}\n\nfunction clockOfDay(iso: string, options: ExportOptions): string {\n const at = new Date(iso);\n if (Number.isNaN(at.getTime())) return \"\";\n return at.toLocaleTimeString(options.locale, {\n hour: \"numeric\",\n minute: \"2-digit\",\n second: \"2-digit\",\n ...(options.timeZone !== undefined ? { timeZone: options.timeZone } : {}),\n });\n}\n\nfunction vttStamp(offsetMs: number): string {\n const total = Math.max(0, Math.round(offsetMs));\n const h = Math.floor(total / 3_600_000);\n const m = Math.floor((total % 3_600_000) / 60_000);\n const s = Math.floor((total % 60_000) / 1000);\n const milli = total % 1000;\n return `${String(h).padStart(2, \"0\")}:${String(m).padStart(2, \"0\")}:${String(s).padStart(2, \"0\")}.${String(milli).padStart(3, \"0\")}`;\n}\n\n/**\n * The transcript as a document. `txt` and `md` group consecutive lines by one\n * speaker with the clock of day; `vtt` is WebVTT cued from the recording's\n * start when a recording exists (so it plays as captions over it), otherwise\n * from the meeting's start — and a cue ends where the next line begins.\n */\nexport function transcriptDocument(\n bundle: Pick<MeetingRecordBundle, \"meeting\" | \"transcript\" | \"recording\" | \"names\">,\n format: TranscriptFormat,\n options: ExportOptions = {},\n): string {\n const names = options.names ?? bundle.names;\n const lines = bundle.transcript.filter((line) => line.text.trim().length > 0);\n const speaker = (line: TranscriptSegment) => displayNameFor(names, line.identity, line.speaker);\n\n if (format === \"vtt\") {\n const zeroIso =\n bundle.recording?.state === \"available\" && bundle.recording.startedAt !== null\n ? bundle.recording.startedAt\n : (bundle.meeting.startedAt ?? lines[0]?.startedAt ?? null);\n const zero = ms(zeroIso) ?? 0;\n const cues = [\"WEBVTT\", \"\"];\n lines.forEach((line, index) => {\n const start = (ms(line.startedAt) ?? zero) - zero;\n if (start < 0) return;\n const next = lines[index + 1];\n const nextStart = next !== undefined ? (ms(next.startedAt) ?? zero) - zero : start + 4000;\n const end = Math.max(start + 500, Math.min(nextStart, start + 10_000));\n cues.push(`${vttStamp(start)} --> ${vttStamp(end)}`);\n cues.push(`<v ${speaker(line).replace(/[<>]/g, \"\")}>${line.text.replace(/-->/g, \"->\")}`);\n cues.push(\"\");\n });\n return cues.join(\"\\n\");\n }\n\n const out: string[] = [];\n const title = bundle.meeting.title;\n out.push(format === \"md\" ? `# ${title} — transcript` : `${title} — transcript`);\n out.push(\"\");\n let last: string | null = null;\n for (const line of lines) {\n if (line.identity !== last) {\n if (last !== null) out.push(\"\");\n const who = speaker(line);\n const clock = clockOfDay(line.startedAt, options);\n out.push(format === \"md\" ? `**${who}** · ${clock}` : `${who} (${clock})`);\n last = line.identity;\n }\n out.push(line.text.trim());\n }\n if (lines.length === 0) out.push(\"No transcript was captured for this meeting.\");\n return `${out.join(\"\\n\")}\\n`;\n}\n\nfunction bullet(note: MeetingNote): string {\n const owner = note.assigneeDisplayName !== null ? ` — ${note.assigneeDisplayName}` : \"\";\n return `- ${note.text.trim()}${owner}`;\n}\n\n/**\n * The meeting's notes as Markdown: when, who attended, the summary, decisions\n * and action items (with owners), and the link back. What a person pastes into\n * a doc or an email; also the source for PDF / Word export.\n */\nexport function notesDocument(\n bundle: Pick<\n MeetingRecordBundle,\n \"meeting\" | \"summary\" | \"decisions\" | \"actionItems\" | \"attendees\" | \"names\"\n >,\n options: { readonly link?: string | null; readonly when?: string | null } = {},\n): string {\n const out: string[] = [`# ${bundle.meeting.title}`, \"\"];\n if (options.when) out.push(`_${options.when}_`, \"\");\n // One name per PERSON — a rejoin is not a second attendee.\n const people = uniqueAttendees(\n bundle.attendees.filter((person) => !person.isAgent && person.joinedAt !== null),\n bundle.names,\n ).map((person) => displayNameFor(bundle.names, person.identity, person.displayName));\n if (people.length > 0) out.push(`**Attended:** ${people.join(\", \")}`, \"\");\n out.push(\"## Summary\", \"\", bundle.summary?.text.trim() || \"No summary was written.\", \"\");\n out.push(\"## Decisions\", \"\");\n out.push(...(bundle.decisions.length > 0 ? bundle.decisions.map(bullet) : [\"None recorded.\"]), \"\");\n out.push(\"## Action items\", \"\");\n out.push(\n ...(bundle.actionItems.length > 0 ? bundle.actionItems.map(bullet) : [\"None recorded.\"]),\n \"\",\n );\n if (options.link) out.push(`[Open the meeting record](${options.link})`, \"\");\n return out.join(\"\\n\");\n}\n\n/** How long the meeting ran, in words (\"42 minutes\"), or null when unknown. */\nexport function meetingLength(meeting: MeetingRecord): string | null {\n const start = ms(meeting.startedAt);\n const end = ms(meeting.endedAt);\n if (start === null || end === null || end < start) return null;\n return formatDurationMs(end - start, { style: \"long\" });\n}\n\n/* ───────────────────────── Saved chat ───────────────────────── */\n\nexport interface MeetingChatHistory {\n readonly messages: readonly RoomChatMessage[];\n /** The server's refusal, in its words, when the history could not be read. */\n readonly refusal: { readonly message: string; readonly remedy: string } | null;\n}\n\n/**\n * The saved chat of a finished meeting (`GET /v1/meet/chat`). Private messages\n * are never saved, by design, so they are never here. A refusal is returned as\n * data — the record still renders everything else.\n */\nexport async function loadMeetingChat(\n api: MeetApi,\n meetingId: MeetingId,\n roomToken: string | null = null,\n): Promise<MeetingChatHistory> {\n const operation = \"meet.loadMeetingChat\";\n let response: Response;\n try {\n response = await api.request({\n path: `${MEET_ROUTES.chat}?meeting_id=${encodeURIComponent(meetingId)}`,\n method: \"GET\",\n operation,\n requireAuth: roomToken === null,\n ...(roomToken !== null ? { headers: { [ROOM_TOKEN_HEADER]: roomToken } } : {}),\n });\n } catch (error) {\n return {\n messages: [],\n refusal: {\n message: `The chat could not be read (${(error as Error).message}).`,\n remedy: (error as { remedy?: string }).remedy ?? \"Reload the page.\",\n },\n };\n }\n if (!response.ok) {\n let body: unknown = null;\n try {\n body = await response.json();\n } catch {\n body = null;\n }\n const said = readServerRefusal(body);\n return {\n messages: [],\n refusal: {\n message: said?.reason ?? `The chat could not be read (the server answered ${response.status}).`,\n remedy: said?.remedy || \"Reload the page.\",\n },\n };\n }\n const payload = (await response.json()) as { messages?: unknown };\n const rows = Array.isArray(payload.messages) ? payload.messages : [];\n return {\n messages: rows\n .map((row) =>\n typeof row === \"object\" && row !== null ? chatFromRow(row as Record<string, unknown>) : null,\n )\n .filter((message): message is RoomChatMessage => message !== null),\n refusal: null,\n };\n}\n\n/* ───────────────────────── The recap email ───────────────────────── */\n\n/** One person the recap can go to, as the server resolved them. */\nexport interface FollowUpRecipient {\n /** Stable key for the choice: `user:<id>` or `email:<address>`. */\n readonly key: string;\n readonly name: string;\n /** The address, when this reader may see it (the host sees their guests'). */\n readonly email: string | null;\n readonly userId: string | null;\n /** `invitee`, `attendee` or both — where the server found them. */\n readonly sources: readonly (\"invitee\" | \"attendee\")[];\n /** False when the server has no way to reach them (no account, no address). */\n readonly reachable: boolean;\n}\n\n/** The draft the host reviews. The text is the wrap-up's own, arranged. */\nexport interface FollowUpDraft {\n readonly subject: string;\n readonly body: string;\n readonly recipients: readonly FollowUpRecipient[];\n /** False while the wrap-up has not been written — the draft says so. */\n readonly wrapUpWritten: boolean;\n /** When a recap for this meeting was last sent, and to how many. */\n readonly lastSent: { readonly at: string; readonly count: number } | null;\n}\n\nexport interface FollowUpSendResult {\n readonly dryRun: boolean;\n /** Recipients the send queued (or, on a dry run, would queue). */\n readonly queued: readonly string[];\n /** Recipient keys skipped, each with the reason. */\n readonly skipped: readonly { readonly key: string; readonly reason: string }[];\n}\n\nfunction refusalOf(response: Response, operation: string): Promise<MeetError> {\n return refusalFromResponse(response, operation, \"Nothing was sent. Try again.\");\n}\n\nfunction asRecipient(row: Record<string, unknown>): FollowUpRecipient {\n const sources = Array.isArray(row[\"sources\"]) ? (row[\"sources\"] as string[]) : [];\n return {\n key: String(row[\"key\"] ?? \"\"),\n name: String(row[\"name\"] ?? \"\"),\n email: typeof row[\"email\"] === \"string\" ? row[\"email\"] : null,\n userId: typeof row[\"user_id\"] === \"string\" ? row[\"user_id\"] : null,\n sources: sources.filter((s): s is \"invitee\" | \"attendee\" => s === \"invitee\" || s === \"attendee\"),\n reachable: row[\"reachable\"] !== false,\n };\n}\n\n/** The recap draft for a finished meeting. The host, a co-host or an editor. */\nexport async function loadFollowUpDraft(api: MeetApi, meetingId: MeetingId): Promise<FollowUpDraft> {\n const operation = \"meet.loadFollowUpDraft\";\n const response = await api.request({\n path: meetingPath(MEET_ROUTES.meetingFollowUp, meetingId),\n method: \"GET\",\n requireAuth: true,\n operation,\n });\n if (!response.ok) throw await refusalOf(response, operation);\n const body = (await response.json()) as Record<string, unknown>;\n const last = body[\"last_sent\"] as Record<string, unknown> | null | undefined;\n return {\n subject: String(body[\"subject\"] ?? \"\"),\n body: String(body[\"body\"] ?? \"\"),\n recipients: (Array.isArray(body[\"recipients\"]) ? body[\"recipients\"] : []).map((row) =>\n asRecipient(row as Record<string, unknown>),\n ),\n wrapUpWritten: body[\"wrap_up_written\"] === true,\n lastSent:\n last && typeof last[\"at\"] === \"string\"\n ? { at: last[\"at\"], count: typeof last[\"count\"] === \"number\" ? last[\"count\"] : 0 }\n : null,\n };\n}\n\n/**\n * Send the recap the host reviewed. `dryRun` resolves every recipient and\n * renders every email but queues nothing — how a test proves the path without\n * mailing a real inbox. Never called automatically.\n */\nexport async function sendFollowUp(\n api: MeetApi,\n meetingId: MeetingId,\n input: {\n readonly subject: string;\n readonly body: string;\n readonly recipientKeys: readonly string[];\n readonly dryRun?: boolean;\n },\n): Promise<FollowUpSendResult> {\n const operation = \"meet.sendFollowUp\";\n const response = await api.request({\n path: meetingPath(MEET_ROUTES.meetingFollowUp, meetingId),\n method: \"POST\",\n requireAuth: true,\n operation,\n body: {\n subject: input.subject,\n body: input.body,\n recipient_keys: [...input.recipientKeys],\n dry_run: input.dryRun === true,\n },\n });\n if (!response.ok) throw await refusalOf(response, operation);\n const body = (await response.json()) as Record<string, unknown>;\n return {\n dryRun: body[\"dry_run\"] === true,\n queued: Array.isArray(body[\"queued\"]) ? (body[\"queued\"] as string[]) : [],\n skipped: Array.isArray(body[\"skipped\"])\n ? (body[\"skipped\"] as Record<string, unknown>[]).map((row) => ({\n key: String(row[\"key\"] ?? \"\"),\n reason: String(row[\"reason\"] ?? \"\"),\n }))\n : [],\n };\n}\n","/**\n * PRESENTATION HELPERS specific to a CALL. Pure, tested, and shared by every\n * surface — so a roster line reads the same in the meeting, in the history\n * list, and in the notification.\n *\n * The GENERIC formatters this file used to define — `formatDuration`,\n * `getInitials`, `avatarPaletteIndex` — moved to `@ai-matrx/kit/format` on\n * 2026-09-07 (duplication census H1). They were byte-for-byte duplicated in\n * `@ai-matrx/messaging`, and because two packages claimed them, ~65 host\n * twins across six repos had no correct owner to point at: no surface should\n * take a dependency on the video-calling package to print a duration. Nothing\n * is re-exported from here — import `@ai-matrx/kit/format` directly.\n */\n\nimport type { CallState, MeetParticipant } from \"./types\";\n\n/** \"Ana, Ben and 3 others\" — the roster line, never a raw array join. */\nexport function participantSummary(participants: readonly MeetParticipant[]): string {\n const names = participants.filter((p) => !p.isLocal).map((p) => p.displayName);\n if (names.length === 0) return \"Just you\";\n if (names.length === 1) return names[0] ?? \"\";\n if (names.length === 2) return `${names[0]} and ${names[1]}`;\n return `${names[0]}, ${names[1]} and ${names.length - 2} ${names.length - 2 === 1 ? \"other\" : \"others\"}`;\n}\n\n/** What a settled call says in history. One sentence per terminal state. */\nexport function callStateLabel(state: CallState, outgoing: boolean): string {\n switch (state) {\n case \"dialing\":\n case \"ringing\":\n return outgoing ? \"Calling…\" : \"Incoming call\";\n case \"connecting\":\n return \"Connecting…\";\n case \"active\":\n return \"In call\";\n case \"declined\":\n return outgoing ? \"Declined\" : \"You declined\";\n case \"missed\":\n return outgoing ? \"No answer\" : \"Missed call\";\n case \"busy\":\n return outgoing ? \"On another call\" : \"You were busy\";\n case \"cancelled\":\n return outgoing ? \"Cancelled\" : \"Cancelled by caller\";\n case \"ended\":\n return \"Call ended\";\n case \"failed\":\n return \"Call failed\";\n default:\n return \"Call\";\n }\n}\n\n/** \"2 waiting\" for the lobby badge — plural handled once, not per surface. */\nexport function countLabel(count: number, singular: string, plural = `${singular}s`): string {\n return `${count} ${count === 1 ? singular : plural}`;\n}\n","\"use client\";\n\n/**\n * INLINED SVGs — no icon-library dependency, ever (C19).\n *\n * The tap-target precedent: ~60 buttons, all inlined, a fraction of a percent\n * of bloat and zero version-skew risk. These are Lucide-shaped paths, adapted;\n * they inherit `currentColor` so the token contract, not an icon prop, decides\n * every color.\n */\n\nimport type { SVGProps } from \"react\";\n\ntype IconProps = SVGProps<SVGSVGElement>;\n\nfunction Icon({ children, ...props }: IconProps): React.ReactElement {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n {...props}\n >\n {children}\n </svg>\n );\n}\n\nexport function MicIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\" />\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <path d=\"M12 19v3\" />\n </Icon>\n );\n}\n\nexport function MicOffIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M2 2l20 20\" />\n <path d=\"M9 9v3a3 3 0 0 0 5.12 2.12\" />\n <path d=\"M15 9.34V5a3 3 0 0 0-5.94-.6\" />\n <path d=\"M19 10v2a7 7 0 0 1-.11 1.23M5 10v2a7 7 0 0 0 11 5.66\" />\n <path d=\"M12 19v3\" />\n </Icon>\n );\n}\n\nexport function CameraIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"m23 7-7 5 7 5V7Z\" />\n <rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\" />\n </Icon>\n );\n}\n\nexport function CameraOffIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M2 2l20 20\" />\n <path d=\"M10.66 5H14a2 2 0 0 1 2 2v3.34l1 1L23 7v10\" />\n <path d=\"M16 16a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h2\" />\n </Icon>\n );\n}\n\nexport function ScreenShareIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"14\" rx=\"2\" />\n <path d=\"M8 21h8M12 17v4\" />\n <path d=\"M12 13V8m0 0-2.5 2.5M12 8l2.5 2.5\" />\n </Icon>\n );\n}\n\nexport function PhoneIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6A19.79 19.79 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.9.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92Z\" />\n </Icon>\n );\n}\n\nexport function PhoneOffIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M2 2l20 20\" />\n <path d=\"M10.68 13.31a16 16 0 0 0 3.41 2.6l1.27-1.27a2 2 0 0 1 2.11-.45c.9.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.42 19.42 0 0 1-3.33-2.67\" />\n <path d=\"M5.53 5.53A19.79 19.79 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91\" />\n </Icon>\n );\n}\n\nexport function HandIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M18 11V6a2 2 0 0 0-4 0v5\" />\n <path d=\"M14 10V4a2 2 0 0 0-4 0v7\" />\n <path d=\"M10 10.5V6a2 2 0 0 0-4 0v8\" />\n <path d=\"M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2a8 8 0 0 1-8-8v-1a2 2 0 1 1 4 0\" />\n </Icon>\n );\n}\n\nexport function ChatIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2Z\" />\n </Icon>\n );\n}\n\nexport function PeopleIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2\" />\n <circle cx=\"9\" cy=\"7\" r=\"4\" />\n <path d=\"M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75\" />\n </Icon>\n );\n}\n\nexport function RecordIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"8\" fill=\"currentColor\" stroke=\"none\" />\n </Icon>\n );\n}\n\nexport function SparklesIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M12 3l1.9 4.6L18.5 9.5l-4.6 1.9L12 16l-1.9-4.6L5.5 9.5l4.6-1.9L12 3Z\" />\n <path d=\"M19 15l.9 2.1 2.1.9-2.1.9-.9 2.1-.9-2.1-2.1-.9 2.1-.9L19 15Z\" />\n </Icon>\n );\n}\n\nexport function LockIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <rect x=\"4\" y=\"10\" width=\"16\" height=\"11\" rx=\"2\" />\n <path d=\"M8 10V7a4 4 0 0 1 8 0v3\" />\n </Icon>\n );\n}\n\nexport function LayoutIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" />\n <path d=\"M3 9h18M9 21V9\" />\n </Icon>\n );\n}\n\nexport function SettingsIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.6a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z\" />\n </Icon>\n );\n}\n\nexport function CheckIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M20 6 9 17l-5-5\" />\n </Icon>\n );\n}\n\nexport function CloseIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </Icon>\n );\n}\n\nexport function PinIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M12 17v5\" />\n <path d=\"M9 2h6l-1 6 3.5 3.5V14H6.5v-2.5L10 8 9 2Z\" />\n </Icon>\n );\n}\n\nexport function WifiLowIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M12 20h.01\" />\n <path d=\"M8.5 16.5a5 5 0 0 1 7 0\" />\n </Icon>\n );\n}\n\n/* Meet wave 2 */\n\nexport function SmileIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M8 14s1.5 2 4 2 4-2 4-2\" />\n <line x1=\"9\" x2=\"9.01\" y1=\"9\" y2=\"9\" />\n <line x1=\"15\" x2=\"15.01\" y1=\"9\" y2=\"9\" />\n </Icon>\n );\n}\n\nexport function MoreIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"19\" cy=\"12\" r=\"1\" />\n <circle cx=\"5\" cy=\"12\" r=\"1\" />\n </Icon>\n );\n}\n\nexport function SearchIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </Icon>\n );\n}\n\nexport function KeyboardIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M10 8h.01M12 12h.01M14 8h.01M16 12h.01M18 8h.01M6 8h.01M7 16h10M8 12h.01\" />\n <rect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\" />\n </Icon>\n );\n}\n\nexport function SpotlightIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M12 2 15 8.5 22 9.3 17 14 18.2 21 12 17.6 5.8 21 7 14 2 9.3 9 8.5Z\" />\n </Icon>\n );\n}\n\nexport function SignalIcon({ bars, ...props }: IconProps & { bars: 0 | 1 | 2 | 3 }): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M4 20v-2\" opacity={bars >= 1 ? 1 : 0.3} />\n <path d=\"M10 20v-6\" opacity={bars >= 2 ? 1 : 0.3} />\n <path d=\"M16 20V9\" opacity={bars >= 3 ? 1 : 0.3} />\n <path d=\"M22 20V4\" opacity={bars >= 3 ? 1 : 0.3} />\n </Icon>\n );\n}\n\nexport function SpeakerIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M11 5 6 9H2v6h4l5 4V5Z\" />\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\" />\n <path d=\"M19.07 4.93a10 10 0 0 1 0 14.14\" />\n </Icon>\n );\n}\n\nexport function FlagIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z\" />\n <line x1=\"4\" x2=\"4\" y1=\"22\" y2=\"15\" />\n </Icon>\n );\n}\n\nexport function PencilIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <path d=\"M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z\" />\n </Icon>\n );\n}\n","/**\n * THE MESSAGING SEAM — a call invitation is an ACTIONABLE MESSAGE (D8).\n *\n * `@ai-matrx/messaging` deliberately knows nothing about meetings; its action\n * registry exists so packages like this one can add a kind without messaging\n * learning about them. This file is that registration, and it is the whole\n * coupling between the two packages.\n *\n * Why an invitation is a message and not only a ring: a ring is EPHEMERAL. If\n * you were away from your desk, a broadcast that expired is gone, and \"someone\n * tried to reach me\" is exactly the information you most needed. The message is\n * the durable half — it is still in the thread tomorrow, with the outcome\n * stamped on it.\n *\n * 🚨 **THE PAYLOAD IS NOT AUTHORIZATION.** The chip's payload says what was\n * ASKED, never what is ALLOWED. The handler re-resolves the invite through the\n * repository (an auth-checked RPC) before it joins anything. Trusting the\n * payload would turn any message anyone can send into a room grant.\n *\n * Idempotence is the registry's, not ours: two tabs and a double tap settle\n * ONCE and share one receipt.\n */\n\nimport type { ActionHandler, ActionReceipt } from \"@ai-matrx/messaging\";\nimport type { CallCenter } from \"./calls\";\nimport { MeetError } from \"./errors\";\nimport type { MeetRepository } from \"./repository\";\nimport { asCallId, asUserId, type CallInvite, type CallMode } from \"./types\";\n\nexport const CALL_INVITE_KIND = \"meet.call-invite\";\nexport const CALL_INVITE_VERSION = 1;\n\nexport interface CallInvitePayload {\n readonly invite_id: string;\n readonly room_name: string;\n readonly mode: CallMode;\n readonly caller_name: string;\n readonly expires_at: string;\n}\n\n/** The `action_data` a caller attaches to the invitation message. */\nexport function callInviteAction(invite: CallInvite): {\n readonly kind: string;\n readonly version: number;\n readonly payload: CallInvitePayload;\n} {\n return {\n kind: CALL_INVITE_KIND,\n version: CALL_INVITE_VERSION,\n payload: {\n invite_id: invite.id,\n room_name: invite.roomName,\n mode: invite.mode,\n caller_name: invite.callerName,\n expires_at: invite.expiresAt,\n },\n };\n}\n\n/** The message body. Readable on a surface that cannot render the chips. */\nexport function callInviteText(invite: CallInvite): string {\n return invite.mode === \"video\"\n ? `${invite.callerName} started a video call`\n : `${invite.callerName} started an audio call`;\n}\n\nexport interface CallInviteHandlerOptions {\n calls: CallCenter;\n repository: MeetRepository;\n /** Called after a successful accept, with the room to enter. */\n onJoin: (invite: CallInvite) => void | Promise<void>;\n now?: (() => number) | undefined;\n}\n\nexport function createCallInviteHandler(\n options: CallInviteHandlerOptions,\n): ActionHandler<CallInvitePayload> {\n const now = options.now ?? (() => Date.now());\n\n return {\n kind: CALL_INVITE_KIND,\n versions: [CALL_INVITE_VERSION],\n choices: (payload) => {\n // An EXPIRED invite renders no chips. Offering \"Join\" for a call that\n // ended twenty minutes ago is a dead end with a friendly face.\n if (Date.parse(payload.expires_at) < now()) return [];\n return [\n { id: \"join\", label: payload.mode === \"video\" ? \"Join video\" : \"Join call\", tone: \"primary\" },\n { id: \"decline\", label: \"Decline\", tone: \"neutral\" },\n ];\n },\n summarize: (payload) =>\n payload.mode === \"video\"\n ? `${payload.caller_name} started a video call`\n : `${payload.caller_name} started an audio call`,\n execute: async (payload, context): Promise<ActionReceipt> => {\n const settledAt = new Date(now()).toISOString();\n const inviteId = asCallId(payload.invite_id);\n\n // RE-RESOLVE. The payload told us what to look for; the database tells us\n // whether it is still true and whether this actor may act on it.\n // `context.actorId` is messaging's branded UserId; ours is a distinct\n // brand over the same string. Re-branding through the constructor is the\n // honest crossing — a cast between two brands would compile today and\n // hide a genuine mismatch the day either package changes its identity.\n const pending = await options.repository.pendingInvites(asUserId(String(context.actorId)));\n const live = pending.find((invite) => invite.id === inviteId) ?? null;\n\n if (live === null) {\n return {\n kind: CALL_INVITE_KIND,\n messageId: context.messageId,\n actorId: context.actorId,\n outcome: \"unavailable\",\n label: \"This call has ended\",\n settledAt,\n detail:\n \"The invite is no longer ringing — it was answered elsewhere, cancelled, or it \" +\n \"timed out. The chips are replaced by the outcome rather than left clickable.\",\n };\n }\n\n if (context.choice === \"decline\") {\n await options.calls.decline(inviteId);\n return {\n kind: CALL_INVITE_KIND,\n messageId: context.messageId,\n actorId: context.actorId,\n outcome: \"declined\",\n label: \"Declined\",\n settledAt,\n };\n }\n\n const accepted = await options.calls.accept(inviteId, live.mode);\n await options.onJoin(accepted);\n return {\n kind: CALL_INVITE_KIND,\n messageId: context.messageId,\n actorId: context.actorId,\n outcome: \"applied\",\n label: \"Joined\",\n settledAt,\n };\n },\n };\n}\n\n/**\n * A meeting invitation — the scheduled twin. Deliberately NOT the same kind: a\n * scheduled meeting's chip must never say \"Join call\" three days early, and a\n * receiver that only understands calls must render NOTHING for it rather than a\n * button it cannot honor.\n */\nexport const MEETING_INVITE_KIND = \"meet.meeting-invite\";\nexport const MEETING_INVITE_VERSION = 1;\n\nexport interface MeetingInvitePayload {\n readonly meeting_id: string;\n readonly slug: string;\n readonly title: string;\n readonly scheduled_for: string | null;\n readonly link: string;\n}\n\nexport function meetingInviteAction(payload: MeetingInvitePayload): {\n readonly kind: string;\n readonly version: number;\n readonly payload: MeetingInvitePayload;\n} {\n return { kind: MEETING_INVITE_KIND, version: MEETING_INVITE_VERSION, payload };\n}\n\nexport interface MeetingInviteHandlerOptions {\n onOpen: (payload: MeetingInvitePayload) => void | Promise<void>;\n now?: (() => number) | undefined;\n}\n\nexport function createMeetingInviteHandler(\n options: MeetingInviteHandlerOptions,\n): ActionHandler<MeetingInvitePayload> {\n const now = options.now ?? (() => Date.now());\n return {\n kind: MEETING_INVITE_KIND,\n versions: [MEETING_INVITE_VERSION],\n // A DURABLE LINK NEVER EXPIRES (R3) — the chip stays useful after the\n // meeting too, because that is when people go looking for the notes.\n choices: () => [{ id: \"open\", label: \"Open meeting\", tone: \"primary\" }],\n summarize: (payload) =>\n payload.scheduled_for === null\n ? payload.title\n : `${payload.title} — ${payload.scheduled_for}`,\n execute: async (payload, context): Promise<ActionReceipt> => {\n if (payload.slug.length === 0) {\n throw new MeetError(\n \"invalid-response\",\n \"meet.meeting-invite: the payload carries no slug\",\n \"A meeting invitation without a durable slug cannot be opened. Fix the sender; \" +\n \"never synthesize a link on the receiving side.\",\n );\n }\n await options.onOpen(payload);\n return {\n kind: MEETING_INVITE_KIND,\n messageId: context.messageId,\n actorId: context.actorId,\n outcome: \"applied\",\n label: \"Opened\",\n settledAt: new Date(now()).toISOString(),\n };\n },\n };\n}\n","/**\n * MEET WAVE 1 — the two server calls a management screen makes (0.8).\n *\n * Every WRITE (schedule, edit, reschedule, cancel, archive, occurrence change,\n * invite, answer) goes straight to the database through `MeetRepository` — the\n * database decides who may. What a browser cannot do is send an email with a\n * calendar object in it, so after any of those writes a screen calls\n * `announceMeeting`: the server tells each invitee exactly what they have not\n * been told (invitation, update or cancellation, each with its `.ics`), and\n * re-queues reminders. It is idempotent — call it after every save.\n */\n\nimport type { MeetApi } from \"./api\";\nimport { refusalFromResponse } from \"./ai\";\nimport { MeetError } from \"./errors\";\nimport { MEET_ROUTES, meetingPath } from \"./tokens\";\nimport type { MeetingId } from \"./types\";\n\nexport interface AnnounceResult {\n readonly invitations: number;\n readonly updates: number;\n readonly cancellations: number;\n readonly alreadyCurrent: number;\n readonly remindersQueued: number;\n readonly remindersCancelled: number;\n}\n\nfunction refusal(response: Response, operation: string): Promise<MeetError> {\n return refusalFromResponse(\n response,\n operation,\n \"The meeting itself is saved — only the telling failed. Try again; the call is idempotent.\",\n );\n}\n\nfunction count(body: Record<string, unknown>, key: string): number {\n const value = body[key];\n return typeof value === \"number\" ? value : 0;\n}\n\n/** Bring every invitee's inbox and calendar up to date. The host, a co-host or an editor. */\nexport async function announceMeeting(api: MeetApi, meetingId: MeetingId): Promise<AnnounceResult> {\n const operation = \"meet.announceMeeting\";\n const response = await api.request({\n path: meetingPath(MEET_ROUTES.meetingAnnounce, meetingId),\n method: \"POST\",\n requireAuth: true,\n operation,\n });\n if (!response.ok) throw await refusal(response, operation);\n const body = (await response.json()) as Record<string, unknown>;\n return {\n invitations: count(body, \"invitations\"),\n updates: count(body, \"updates\"),\n cancellations: count(body, \"cancellations\"),\n alreadyCurrent: count(body, \"already_current\"),\n remindersQueued: count(body, \"reminders_queued\"),\n remindersCancelled: count(body, \"reminders_cancelled\"),\n };\n}\n\n/**\n * Put a one-off meeting on the caller's own connected Google Calendar. GATED by\n * the server to Google's review accounts while the Calendar scope is in review —\n * a refusal is a `forbidden` MeetError carrying the server's sentence. Everyone\n * already gets the meeting into any calendar through the invitation's `.ics`.\n */\nexport async function pushMeetingToGoogleCalendar(\n api: MeetApi,\n meetingId: MeetingId,\n target: { connectionId: string; calendarId?: string },\n): Promise<Record<string, unknown>> {\n const operation = \"meet.pushMeetingToGoogleCalendar\";\n const response = await api.request({\n path: meetingPath(MEET_ROUTES.meetingGoogleCalendar, meetingId),\n method: \"POST\",\n requireAuth: true,\n operation,\n body: { connection_id: target.connectionId, calendar_id: target.calendarId ?? \"primary\" },\n });\n if (!response.ok) throw await refusal(response, operation);\n return (await response.json()) as Record<string, unknown>;\n}\n"],"mappings":"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","names":["text","row","refusal","ms","pending","current","deviceId","text","existing","refusal","options","text","refusal","text","deviceId","refusal","text","text","deviceId","useCallback","useEffect","useMemo","useRef","useState","count","when","refusal","useCallback","text","useState","useMemo","useEffect","useRef","useEffect","useMemo","useRef","useState","formatDurationMs","formatDurationMs","text","formatDurationMs","count","jsx","jsx","jsxs","useState","useEffect","useRef","text","refusal","deviceId","formatDurationMs","when","useMemo","notice"]}
|