@defcomm/meetingsdk 0.3.3 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/react/useLocalParticipant.tsx","../src/react/MeetingProvider.tsx","../src/config/ws.ts","../src/core/ActiveSpeakerDetector.ts","../src/core/MeetingState.ts","../src/core/SFUClient.ts","../src/core/VideoCore.ts","../src/react/useMeetingStore.ts","../src/react/useMeeting.ts","../src/react/useParticipants.ts","../src/react/useRemoteMedia.ts","../src/react/useMeetingPreview.ts"],"sourcesContent":["export { useLocalParticipant } from \"./react/useLocalParticipant\";\n\n// Core exports\nexport { VideoSDKCore } from \"./core/VideoCore\";\nexport { SFUClient } from \"./core/SFUClient\";\nexport type {\n SFUConnectionState,\n TrackInfo,\n ParticipantInfo,\n} from \"./core/SFUClient\";\nexport { MeetingState } from \"./core/MeetingState\";\nexport type {\n Participant,\n ChatInput,\n RecordingInfo,\n Reaction,\n MeetingConfig,\n} from \"./types/meeting\";\n\n// React hooks and components\nexport { MeetingProvider, useMeetingContext } from \"./react/MeetingProvider\";\nexport { useMeeting } from \"./react/useMeeting\";\nexport { useParticipants } from \"./react/useParticipants\";\nexport { useRemoteMedia } from \"./react/useRemoteMedia\";\nexport { useMeetingPreview } from \"./react/useMeetingPreview\";\nexport { ActiveSpeakerDetector } from \"./core/ActiveSpeakerDetector\";\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\nimport { Participant } from \"../types/meeting\";\n\nexport const useLocalParticipant = () => {\n const { sdk } = useMeetingContext();\n\n // Guard the initial state to ensure it matches Participant | null\n const [localParticipant, setLocalParticipant] = useState<Participant | null>(\n () => {\n const current = sdk.state.localParticipant;\n return current && current.id ? (current as Participant) : null;\n },\n );\n\n useEffect(() => {\n const unsubscribe = sdk.state.subscribe(\"localParticipant\", () => {\n const current = sdk.state.localParticipant;\n\n // Safe Type-Guard: Only update if the object has a finalized id\n if (current && current.id) {\n setLocalParticipant({ ...current } as Participant);\n } else {\n setLocalParticipant(null);\n }\n });\n\n return unsubscribe;\n }, [sdk]);\n\n const lastStreamRef = useRef<MediaStream | null>(null);\n\n const videoRef = useCallback(\n (video: HTMLVideoElement | null) => {\n if (!video) return;\n\n const stream = localParticipant?.media?.stream;\n if (!stream) return;\n\n if (lastStreamRef.current === stream) return;\n lastStreamRef.current = stream;\n\n video.srcObject = stream;\n video.autoplay = true;\n video.playsInline = true;\n\n video.play().catch((err) => {\n console.warn(`Autoplay failed for local view:`, err);\n });\n },\n [localParticipant?.media?.stream],\n );\n\n return {\n participant: localParticipant,\n videoRef,\n };\n};\n","import React, { createContext, useContext, useMemo, useRef } from \"react\";\nimport { VideoSDKCore } from \"../core/VideoCore\";\nimport {\n ChatInput,\n ChatMessage,\n Reaction,\n MeetingConfig,\n Participant,\n PubSubTopic,\n Recording,\n} from \"../types/meeting\";\nimport { useMeetingStore } from \"./useMeetingStore\";\n\ntype PubSubHandle = {\n messages: ChatMessage[];\n publish: (input: ChatInput) => void;\n};\n\ntype MeetingContextValue = {\n sdk: VideoSDKCore;\n join: (config?: Omit<MeetingConfig, \"participantId\">) => Promise<void>;\n leave: () => void;\n createRoom: (input: {\n name: string;\n description?: string;\n capacity?: number;\n is_private?: boolean;\n }) => Promise<any>;\n getRoom: (roomCode: string) => Promise<any>;\n deleteRoom: (roomCode: string) => Promise<any>;\n\n toggleMic: () => void;\n toggleCam: () => void;\n\n startScreenShare: () => Promise<MediaStream | null>;\n stopScreenShare: () => void;\n\n sendMessage: (input: ChatInput) => void;\n sendReaction: (emoji: string) => void;\n\n room: { id: string | null; name: string | null };\n localParticipant: Participant | null;\n participants: Map<string, Participant>;\n messages: ChatMessage[];\n presenterId: string | null;\n activeSpeakerIds: string[];\n usePubSub: (topic: PubSubTopic) => PubSubHandle;\n approveJoinRequest: (requestId: string) => void;\n rejectJoinRequest: (requestId: string) => void;\n startRecording: () => Promise<void>;\n stopRecording: () => Promise<void>;\n getRecordingStatus: () => Promise<any>;\n onError: (cb: (err: any) => void) => () => void;\n onEntryRequested: (cb: (req: any) => void) => () => void;\n onEntryResponded: (cb: (payload: any, decision?: any) => void) => () => void;\n onMeetingLeft: (cb: () => void) => () => void;\n onTrackStateChanged: (cb: (track: any) => void) => () => void;\n onRecordingStarted: (cb: (recording: Recording) => void) => () => void;\n onRecordingStopped: (cb: (recording: any) => void) => () => void;\n onReaction: (cb: (reaction: Reaction) => void) => () => void;\n onActiveSpeakersChanged: (\n cb: (participantIds: string[]) => void,\n ) => () => void;\n};\n\nconst MeetingContext = createContext<MeetingContextValue | null>(null);\n\nexport const MeetingProvider = ({\n config,\n children,\n}: {\n config: MeetingConfig;\n children: React.ReactNode;\n}) => {\n const sdkRef = useRef<VideoSDKCore | null>(null);\n const errorListeners = useRef(new Set<(err: any) => void>());\n const entryRequestListeners = useRef(new Set<(req: any) => void>());\n const entryResponseListeners = useRef(\n new Set<(payload: any, decision?: any) => void>(),\n );\n const meetingLeftListeners = useRef(new Set<() => void>());\n const trackStateListeners = useRef(new Set<(track: any) => void>());\n const recordingStartedListeners = useRef(new Set<(recording: any) => void>());\n const recordingStoppedListeners = useRef(new Set<(recording: any) => void>());\n const reactionListeners = useRef(new Set<(reaction: Reaction) => void>());\n const activeSpeakerListeners = useRef(\n new Set<(participantIds: string[]) => void>(),\n );\n\n if (!sdkRef.current) {\n sdkRef.current = new VideoSDKCore(\n {\n participantId: config.participantId,\n },\n {\n onError: (err) => {\n errorListeners.current.forEach((fn) => fn(err));\n },\n\n onEntryRequested: (req) => {\n entryRequestListeners.current.forEach((fn) => fn(req));\n },\n\n onEntryResponded: (p, d) => {\n entryResponseListeners.current.forEach((fn) => fn(p, d));\n },\n\n onMeetingLeft: () => {\n meetingLeftListeners.current.forEach((fn) => fn());\n },\n\n onTrackStateChanged: (track) => {\n trackStateListeners.current.forEach((fn) => fn(track));\n },\n\n onRecordingStarted: (recording) => {\n recordingStartedListeners.current.forEach((fn) => fn(recording));\n },\n\n onRecordingStopped: (recording) => {\n recordingStoppedListeners.current.forEach((fn) => fn(recording));\n },\n\n onReaction: (reaction) => {\n reactionListeners.current.forEach((fn) => fn(reaction));\n },\n },\n );\n }\n const sdk = sdkRef.current;\n const activeSpeakerIds = useMeetingStore(sdk.state, \"activeSpeakers\", (s) =>\n Array.from(s.activeSpeakerIds),\n );\n const presenterId = useMeetingStore(\n sdk.state,\n \"presenter\",\n (s) => s.presenterId,\n );\n const participants = useMeetingStore(\n sdk.state,\n \"participants\",\n (s) => s.participants,\n );\n const localParticipant = useMeetingStore(\n sdk.state,\n \"localParticipant\",\n (s) => s.localParticipant,\n );\n const messages = useMeetingStore(sdk.state, \"chat\", (s) =>\n s.getChatMessages(),\n );\n\n const value = useMemo<MeetingContextValue>(() => {\n return {\n sdk,\n join: (joinConfig?: Omit<MeetingConfig, \"participantId\">) =>\n sdk.joinMeeting({\n ...config,\n ...joinConfig,\n }),\n leave: () => sdk.disconnect(),\n createRoom: sdk.createRoom.bind(sdk),\n getRoom: sdk.getRoom.bind(sdk),\n deleteRoom: sdk.deleteRoom.bind(sdk),\n toggleMic: sdk.toggleMic.bind(sdk),\n toggleCam: sdk.toggleCam.bind(sdk),\n startScreenShare: sdk.startScreenShare.bind(sdk),\n stopScreenShare: sdk.stopScreenShare.bind(sdk),\n sendMessage: sdk.sendChatMessage.bind(sdk),\n sendReaction: sdk.sendReaction.bind(sdk),\n\n room: sdk.getMeeting(),\n localParticipant,\n participants,\n messages,\n presenterId,\n activeSpeakerIds,\n usePubSub: (topic: PubSubTopic) => {\n if (topic !== \"SECURE_CHAT\") {\n throw new Error(`Unsupported PubSub argument: \"${topic}\"`);\n }\n return {\n messages: sdk.state.getChatMessages(),\n publish: sdk.sendChatMessage.bind(sdk),\n };\n },\n approveJoinRequest: sdk.approveJoinRequest.bind(sdk),\n rejectJoinRequest: sdk.rejectJoinRequest.bind(sdk),\n startRecording: sdk.startRecording.bind(sdk),\n stopRecording: sdk.stopRecording.bind(sdk),\n getRecordingStatus: sdk.getRecordingStatus.bind(sdk),\n\n onError: (cb: (err: any) => void) => {\n errorListeners.current.add(cb);\n\n return () => {\n errorListeners.current.delete(cb);\n };\n },\n\n onEntryRequested: (cb: (err: any) => void) => {\n entryRequestListeners.current.add(cb);\n\n return () => {\n entryRequestListeners.current.delete(cb);\n };\n },\n onEntryResponded: (cb: (err: any) => void) => {\n entryResponseListeners.current.add(cb);\n\n return () => {\n entryResponseListeners.current.delete(cb);\n };\n },\n onMeetingLeft: (cb: () => void) => {\n meetingLeftListeners.current.add(cb);\n return () => {\n meetingLeftListeners.current.delete(cb);\n };\n },\n onTrackStateChanged: (cb: (track: any) => void) => {\n trackStateListeners.current.add(cb);\n return () => trackStateListeners.current.delete(cb);\n },\n onRecordingStarted: (cb: (recording: any) => void) => {\n recordingStartedListeners.current.add(cb);\n return () => recordingStartedListeners.current.delete(cb);\n },\n onRecordingStopped: (cb: (recording: any) => void) => {\n recordingStoppedListeners.current.add(cb);\n return () => recordingStoppedListeners.current.delete(cb);\n },\n onReaction: (cb: (reaction: Reaction) => void) => {\n reactionListeners.current.add(cb);\n return () => reactionListeners.current.delete(cb);\n },\n onActiveSpeakersChanged: (cb) => {\n activeSpeakerListeners.current.add(cb);\n\n return () => {\n activeSpeakerListeners.current.delete(cb);\n };\n },\n };\n }, [config, sdk, localParticipant, participants, messages, presenterId]);\n\n return (\n <MeetingContext.Provider value={value}>{children}</MeetingContext.Provider>\n );\n};\n\nexport const useMeetingContext = () => {\n const ctx = useContext(MeetingContext);\n if (!ctx)\n throw new Error(\"useMeetingContext must be used inside <MeetingProvider>\");\n return ctx;\n};\n","/**\n * SDK Configuration for WebSocket and SFU connections\n * Updated to support the new Selective Forwarding Unit (SFU) architecture\n */\n\nexport interface SDKConfig {\n apiBase: string;\n wsBase: string;\n iceServers?: RTCIceServer[];\n connectionTimeout?: number;\n maxReconnectAttempts?: number;\n}\n\nexport const SDK_CONFIG: SDKConfig = {\n apiBase: \"https://sfu-server.duckdns.org/api\",\n wsBase: \"wss://sfu-server.duckdns.org/ws\",\n // Public STUN/TURN servers (fallback)\n iceServers: [\n { urls: [\"stun:stun.l.google.com:19302\"] },\n { urls: [\"stun:stun1.l.google.com:19302\"] },\n ],\n // Connection and reconnection settings\n connectionTimeout: 10000,\n maxReconnectAttempts: 5,\n};\n","type SpeakerState = {\n participantId: string;\n track: MediaStreamTrack;\n stream: MediaStream;\n source: MediaStreamAudioSourceNode;\n analyser: AnalyserNode;\n data: Float32Array<ArrayBuffer>;\n active: boolean;\n lastActiveAt: number;\n};\n\nexport interface ActiveSpeakerDetectorOptions {\n intervalMs?: number;\n threshold?: number;\n releaseThreshold?: number;\n releaseMs?: number;\n onActiveSpeakersChanged?: (participantIds: string[]) => void;\n}\n\nexport class ActiveSpeakerDetector {\n private audioContext: AudioContext | null = null;\n\n private speakers = new Map<string, SpeakerState>();\n\n private timer: ReturnType<typeof setInterval> | null = null;\n\n private readonly intervalMs: number;\n private readonly threshold: number;\n private readonly releaseThreshold: number;\n private readonly releaseMs: number;\n\n private onActiveSpeakersChanged: (participantIds: string[]) => void;\n\n private lastEmitted = \"\";\n\n constructor(options: ActiveSpeakerDetectorOptions = {}) {\n this.intervalMs = options.intervalMs ?? 100;\n this.threshold = options.threshold ?? 0.025;\n this.releaseThreshold = options.releaseThreshold ?? 0.015;\n this.releaseMs = options.releaseMs ?? 600;\n\n this.onActiveSpeakersChanged =\n options.onActiveSpeakersChanged ?? (() => {});\n }\n\n private ensureAudioContext(): AudioContext {\n if (!this.audioContext) {\n const AudioContextClass =\n window.AudioContext ||\n (\n window as typeof window & {\n webkitAudioContext?: typeof AudioContext;\n }\n ).webkitAudioContext;\n\n if (!AudioContextClass) {\n throw new Error(\"Web Audio API is not supported by this browser\");\n }\n\n this.audioContext = new AudioContextClass();\n }\n\n return this.audioContext;\n }\n\n async resume() {\n if (!this.audioContext) return;\n\n if (this.audioContext.state === \"suspended\") {\n try {\n await this.audioContext.resume();\n } catch {\n // Browser may require a user gesture.\n }\n }\n }\n\n addTrack(participantId: string, track: MediaStreamTrack) {\n if (!participantId) return;\n\n if (track.kind !== \"audio\") return;\n\n this.removeParticipant(participantId);\n const context = this.ensureAudioContext();\n const stream = new MediaStream([track]);\n const source = context.createMediaStreamSource(stream);\n const analyser = context.createAnalyser();\n\n analyser.fftSize = 512;\n analyser.smoothingTimeConstant = 0.65;\n analyser.minDecibels = -90;\n analyser.maxDecibels = -10;\n\n source.connect(analyser);\n\n const data = new Float32Array(analyser.fftSize);\n\n const state: SpeakerState = {\n participantId,\n track,\n stream,\n source,\n analyser,\n data,\n active: false,\n lastActiveAt: 0,\n };\n\n this.speakers.set(participantId, state);\n\n track.addEventListener(\n \"ended\",\n () => {\n this.removeParticipant(participantId);\n },\n { once: true },\n );\n\n this.start();\n\n void this.resume();\n }\n\n removeParticipant(participantId: string) {\n const state = this.speakers.get(participantId);\n\n if (!state) return;\n\n state.active = false;\n\n try {\n state.source.disconnect();\n } catch {\n // Already disconnected.\n }\n\n state.stream.getTracks().forEach((track) => {\n if (track !== state.track) {\n track.stop();\n }\n });\n\n this.speakers.delete(participantId);\n\n this.emitIfChanged();\n }\n\n removeTrack(track: MediaStreamTrack) {\n for (const [participantId, state] of this.speakers) {\n if (state.track === track) {\n this.removeParticipant(participantId);\n }\n }\n }\n\n clear() {\n for (const participantId of this.speakers.keys()) {\n this.removeParticipant(participantId);\n }\n\n this.speakers.clear();\n\n this.stop();\n\n this.emitIfChanged(true);\n }\n\n start() {\n if (this.timer) return;\n\n this.timer = setInterval(() => this.sample(), this.intervalMs);\n }\n\n stop() {\n if (!this.timer) return;\n\n clearInterval(this.timer);\n this.timer = null;\n }\n\n private sample() {\n const now = performance.now();\n\n for (const state of this.speakers.values()) {\n if (\n state.track.readyState !== \"live\" ||\n state.track.muted ||\n !state.track.enabled\n ) {\n if (state.active) {\n state.active = false;\n }\n\n continue;\n }\n\n state.analyser.getFloatTimeDomainData(state.data);\n\n let sumSquares = 0;\n\n for (let i = 0; i < state.data.length; i++) {\n const sample = state.data[i];\n sumSquares += sample * sample;\n }\n\n const rms = Math.sqrt(sumSquares / state.data.length);\n\n if (!state.active) {\n if (rms >= this.threshold) {\n state.active = true;\n state.lastActiveAt = now;\n }\n } else {\n if (rms >= this.releaseThreshold) {\n state.lastActiveAt = now;\n } else if (now - state.lastActiveAt >= this.releaseMs) {\n state.active = false;\n }\n }\n }\n\n this.emitIfChanged();\n }\n\n private getActiveSpeakerIds(): string[] {\n return Array.from(this.speakers.values())\n .filter((speaker) => speaker.active)\n .map((speaker) => speaker.participantId);\n }\n\n private emitIfChanged(force = false) {\n const ids = this.getActiveSpeakerIds().sort();\n\n const key = ids.join(\"|\");\n\n if (!force && key === this.lastEmitted) {\n return;\n }\n\n this.lastEmitted = key;\n\n this.onActiveSpeakersChanged(ids);\n }\n\n async destroy() {\n this.clear();\n\n if (this.audioContext) {\n try {\n await this.audioContext.close();\n } catch {\n // Ignore already closed context.\n }\n\n this.audioContext = null;\n }\n }\n}\n","import {\n ChatMessage,\n Listener,\n Participant,\n ParticipantMedia,\n StateScope,\n} from \"../types/meeting\";\n\ntype LocalParticipantPatch = {\n id?: string;\n name?: string;\n media?: Partial<ParticipantMedia>;\n};\n\nexport class MeetingState {\n participants = new Map<string, Participant>();\n localParticipant: Participant | null = null;\n localStream: MediaStream | null = null;\n chatMessages = new Map<string, ChatMessage>();\n presenterId: string | null = null;\n activeSpeakerIds = new Set<string>();\n\n private listeners = new Map<StateScope, Set<Listener>>();\n\n // ---- reactive system ----\n\n subscribe(scope: StateScope, fn: Listener): () => void {\n if (!this.listeners.has(scope)) {\n this.listeners.set(scope, new Set());\n }\n this.listeners.get(scope)!.add(fn);\n\n return () => {\n this.listeners.get(scope)?.delete(fn);\n };\n }\n\n notify(scope: StateScope) {\n this.listeners.get(scope)?.forEach((fn) => fn());\n }\n\n setPresenterId(id: string | null) {\n if (this.presenterId === id) return;\n this.presenterId = id;\n this.notify(\"presenter\");\n this.notify(\"participants\");\n }\n\n setActiveSpeakers(ids: string[]) {\n const next = new Set(ids);\n\n if (\n next.size === this.activeSpeakerIds.size &&\n [...next].every((id) => this.activeSpeakerIds.has(id))\n ) {\n return;\n }\n\n this.activeSpeakerIds = next;\n\n this.notify(\"activeSpeakers\");\n }\n\n // ---- participants ----\n\n addParticipant(p: Participant) {\n if (this.participants.has(p.id)) return false;\n // Fix: Immutable Map update\n const next = new Map(this.participants);\n next.set(p.id, p);\n this.participants = next;\n\n this.notify(\"participants\");\n return true;\n }\n\n removeParticipant(id: string) {\n // Fix: Immutable Map update\n const next = new Map(this.participants);\n next.delete(id);\n this.participants = next;\n\n this.notify(\"participants\");\n }\n\n updateParticipantMedia(\n id: string,\n patch: Partial<NonNullable<Participant[\"media\"]>>,\n ) {\n const p = this.participants.get(id);\n if (!p) return;\n\n const updated: Participant = {\n ...p,\n media: {\n stream: null,\n screenStream: undefined,\n cameraTrack: undefined,\n screenTrack: undefined,\n audioTrack: undefined,\n micEnabled: true,\n camEnabled: true,\n isScreenSharing: false,\n ...p.media,\n ...patch,\n },\n };\n\n // Keep your clean immutable map update\n const next = new Map(this.participants);\n next.set(id, updated);\n this.participants = next;\n\n this.notify(`participant:${id}`);\n this.notify(\"participants\");\n }\n\n updateLocalParticipant(patch: LocalParticipantPatch) {\n const prev = this.localParticipant;\n\n if (!prev) {\n this.localParticipant = {\n id: patch.id ?? \"\",\n name: patch.name ?? \"\",\n media: {\n stream: patch.media?.stream ?? null, // ◄ FIX: Capture the stream from the patch here\n screenStream: patch.media?.screenStream,\n cameraTrack: patch.media?.cameraTrack,\n screenTrack: patch.media?.screenTrack,\n audioTrack: patch.media?.audioTrack,\n micEnabled: patch.media?.micEnabled ?? true,\n camEnabled: patch.media?.camEnabled ?? true,\n isScreenSharing: patch.media?.isScreenSharing ?? false,\n },\n };\n\n this.notify(\"localParticipant\");\n return;\n }\n\n const prevMedia = prev.media ?? {\n stream: null,\n screenStream: undefined,\n cameraTrack: undefined,\n screenTrack: undefined,\n audioTrack: undefined,\n micEnabled: true,\n camEnabled: true,\n isScreenSharing: false,\n };\n\n const nextMedia: ParticipantMedia = {\n stream: patch.media?.stream ?? prevMedia.stream,\n screenStream: patch.media?.screenStream ?? prevMedia.screenStream,\n cameraTrack: patch.media?.cameraTrack ?? prevMedia.cameraTrack,\n screenTrack: patch.media?.screenTrack ?? prevMedia.screenTrack,\n audioTrack: patch.media?.audioTrack ?? prevMedia.audioTrack,\n micEnabled: patch.media?.micEnabled ?? prevMedia.micEnabled,\n camEnabled: patch.media?.camEnabled ?? prevMedia.camEnabled,\n isScreenSharing:\n patch.media?.isScreenSharing ?? prevMedia.isScreenSharing,\n };\n\n this.localParticipant = {\n ...prev,\n id: patch.id ?? prev.id,\n name: patch.name ?? prev.name,\n media: nextMedia,\n };\n\n this.notify(\"localParticipant\");\n }\n\n // ---- chat ----\n\n addChatMessage(msg: ChatMessage) {\n this.chatMessages.set(msg.id, msg);\n this.notify(\"chat\");\n }\n\n getChatMessages() {\n return Array.from(this.chatMessages.values()).sort(\n (a, b) => a.timestamp - b.timestamp,\n );\n }\n\n clearChat() {\n this.chatMessages.clear();\n this.notify(\"chat\");\n }\n\n // ---- helpers ----\n\n getParticipants() {\n return Array.from(this.participants.values());\n }\n\n getParticipant(id: string) {\n return this.participants.get(id) ?? null;\n }\n\n resetRemoteState() {\n this.participants.clear();\n this.chatMessages.clear();\n this.presenterId = null;\n this.activeSpeakerIds = new Set();\n this.notify(\"participants\");\n this.notify(\"chat\");\n this.notify(\"presenter\");\n this.notify(\"activeSpeakers\");\n }\n}\n","/**\n * DefComm SFU client.\n *\n * Signaling is authoritative for admission/session state.\n * WebRTC peer connections are transport state and are recreated only after a\n * successful join/resume. A transient WebSocket close therefore does NOT\n * destroy the local MediaStream or immediately declare the participant gone.\n */\n\nexport type SFUConnectionState =\n | \"idle\"\n | \"connecting\"\n | \"joining\"\n | \"waiting_approval\"\n | \"connected\"\n | \"reconnecting\"\n | \"leaving\"\n | \"disconnected\";\n\nexport interface TrackInfo {\n track_id: string;\n participant_id: string;\n kind: \"audio\" | \"video\";\n source?: \"camera\" | \"screen\" | \"audio\" | string;\n [key: string]: any;\n}\n\nexport interface ParticipantInfo {\n participant_id: string;\n user_metadata?: { name?: string; [key: string]: any };\n display_name?: string;\n [key: string]: any;\n}\n\nexport interface JoinPendingInfo {\n request_id: string;\n room_code?: string;\n message?: string;\n}\n\ninterface SFUClientOptions {\n apiBase?: string;\n wsBase?: string;\n participantId?: string;\n onStateChange?: (state: SFUConnectionState) => void;\n onParticipantJoined?: (participant: ParticipantInfo) => void;\n onParticipantLeft?: (participant: string | ParticipantInfo) => void;\n onParticipantPresence?: (participantId: string, presence: string) => void;\n onTrackPublished?: (track: TrackInfo) => void;\n onTrackUnpublished?: (track: TrackInfo) => void;\n onRemoteTrack?: (\n track: MediaStreamTrack,\n stream: MediaStream,\n metadata: TrackInfo,\n ) => void;\n onConnected?: (payload: any, resumed: boolean) => void;\n onDisconnected?: () => void;\n onReconnecting?: (attempt: number) => void;\n onJoinPending?: (info: JoinPendingInfo) => void;\n onJoinApproved?: (requestId: string) => void;\n onJoinRejected?: (requestId: string, reason?: string) => void;\n onJoinRequested?: (request: any) => void;\n onScreenShareStarted?: (participantId: string, track?: TrackInfo) => void;\n onScreenShareStopped?: (participantId: string, trackId?: string) => void;\n onTrackStateChanged?: (track: TrackInfo) => void;\n onRecordingStarted?: (recording: {\n recording_id: string;\n started_at: string;\n }) => void;\n onRecordingStopped?: (recording: {\n recording_id: string;\n stopped_at: string;\n }) => void;\n onError?: (error: any) => void;\n onChatMessage?: (message: any) => void;\n onReaction?: (reaction: any) => void;\n onRoomUpdate?: (data: any) => void;\n onParticipantMediaState?: (\n participantId: string,\n audioMuted: boolean,\n videoMuted: boolean,\n ) => void;\n autoSubscribe?: boolean;\n}\n\ntype PeerName = \"publisher\" | \"subscriber\";\ntype JoinWaiter = {\n resolve: (value: any) => void;\n reject: (error: any) => void;\n};\n\nexport class SFUClient {\n private apiBase: string;\n private wsBase: string;\n private participantId: string;\n\n private ws: WebSocket | null = null;\n private publisher: RTCPeerConnection | null = null;\n private subscriber: RTCPeerConnection | null = null;\n\n private localStream: MediaStream | null = null;\n private screenStream: MediaStream | null = null;\n private videoSender: RTCRtpSender | null = null;\n private audioSender: RTCRtpSender | null = null;\n private screenSender: RTCRtpSender | null = null;\n private audioTransceiver: RTCRtpTransceiver | null = null;\n private cameraTransceiver: RTCRtpTransceiver | null = null;\n private screenTransceiver: RTCRtpTransceiver | null = null;\n\n private iceServers: RTCIceServer[] = [];\n private requestId = 0;\n private publisherRevision = 0;\n private screenShareGeneration = 0;\n private currentParticipantId: string | null = null;\n private token: string | null = null;\n private room: string | null = null;\n private resumeToken: string | null = null;\n private pendingJoinRequestId: string | null = null;\n private joinOptions: {\n displayName?: string;\n avatarUrl?: string;\n } = {};\n\n private state: SFUConnectionState = \"idle\";\n private intentionalClose = false;\n private leaveAcknowledged = false;\n private joiningWithResume = false;\n private desiredAudioMuted = false;\n private desiredVideoMuted = false;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectAttempt = 0;\n private maxReconnectAttempts = 8;\n private reconnectBaseMs = 750;\n private joinWaiter: JoinWaiter | null = null;\n\n private transportRecoveryInProgress = false;\n private transportRecoveryTimer: ReturnType<typeof setTimeout> | null = null;\n\n private pendingIce: Record<PeerName, RTCIceCandidateInit[]> = {\n publisher: [],\n subscriber: [],\n };\n\n private subscriberNegotiating = false;\n private offerQueue: any[] = [];\n private subscriptionQueue: string[] = [];\n private subscriptionRunning = false;\n private subscriptionWaiters: Array<{\n trackIds: string[];\n resolve: () => void;\n reject: (error: any) => void;\n }> = [];\n\n private subscribedTracks = new Set<string>();\n private trackMetadata = new Map<string, TrackInfo>();\n private participants = new Map<string, ParticipantInfo>();\n private remoteStreams = new Map<string, MediaStream>();\n private remoteScreenStreams = new Map<string, MediaStream>();\n private trackToParticipant = new Map<string, string>();\n private trackToSource = new Map<string, string>();\n private localTrackIds = new Map<\"audio\" | \"camera\" | \"screen\", string>();\n\n private subscriberStatsTimer: ReturnType<typeof setInterval> | null = null;\n\n private onStateChange: (state: SFUConnectionState) => void;\n private onParticipantJoined: (p: ParticipantInfo) => void;\n private onParticipantLeft: (p: string | ParticipantInfo) => void;\n private onParticipantPresence: (id: string, presence: string) => void;\n private onTrackPublished: (t: TrackInfo) => void;\n private onTrackUnpublished: (t: TrackInfo) => void;\n private onRemoteTrack: (\n t: MediaStreamTrack,\n s: MediaStream,\n m: TrackInfo,\n ) => void;\n private onConnected: (p: any, resumed: boolean) => void;\n private onDisconnected: () => void;\n private onReconnecting: (attempt: number) => void;\n private onJoinPending: (info: JoinPendingInfo) => void;\n private onJoinApproved: (requestId: string) => void;\n private onJoinRejected: (requestId: string, reason?: string) => void;\n private onJoinRequested: (request: any) => void;\n private onScreenShareStarted: (\n participantId: string,\n track?: TrackInfo,\n ) => void;\n private onScreenShareStopped: (\n participantId: string,\n trackId?: string,\n ) => void;\n private onTrackStateChanged: (track: TrackInfo) => void;\n private onRecordingStarted: (recording: {\n recording_id: string;\n started_at: string;\n }) => void;\n private onRecordingStopped: (recording: {\n recording_id: string;\n stopped_at: string;\n }) => void;\n private onError: (e: any) => void;\n private onChatMessage: (message: any) => void;\n private onReaction: (reaction: any) => void;\n private onRoomUpdate: (data: any) => void;\n private onParticipantMediaState: (\n participantId: string,\n audioMuted: boolean,\n videoMuted: boolean,\n ) => void;\n private autoSubscribe: boolean;\n\n constructor(options: SFUClientOptions = {}) {\n this.apiBase = options.apiBase || \"https://api.example.com/api\";\n this.wsBase = options.wsBase || \"wss://api.example.com/ws\";\n this.participantId = options.participantId || this.createId();\n\n this.onStateChange = options.onStateChange || (() => {});\n this.onParticipantJoined = options.onParticipantJoined || (() => {});\n this.onParticipantLeft = options.onParticipantLeft || (() => {});\n this.onParticipantPresence = options.onParticipantPresence || (() => {});\n this.onTrackPublished = options.onTrackPublished || (() => {});\n this.onTrackUnpublished = options.onTrackUnpublished || (() => {});\n this.onRemoteTrack = options.onRemoteTrack || (() => {});\n this.onConnected = options.onConnected || (() => {});\n this.onDisconnected = options.onDisconnected || (() => {});\n this.onReconnecting = options.onReconnecting || (() => {});\n this.onJoinPending = options.onJoinPending || (() => {});\n this.onJoinApproved = options.onJoinApproved || (() => {});\n this.onJoinRejected = options.onJoinRejected || (() => {});\n this.onJoinRequested = options.onJoinRequested || (() => {});\n this.onScreenShareStarted = options.onScreenShareStarted || (() => {});\n this.onScreenShareStopped = options.onScreenShareStopped || (() => {});\n this.onTrackStateChanged = options.onTrackStateChanged || (() => {});\n this.onRecordingStarted = options.onRecordingStarted || (() => {});\n this.onRecordingStopped = options.onRecordingStopped || (() => {});\n this.onError = options.onError || console.error;\n this.onChatMessage = options.onChatMessage || (() => {});\n this.onReaction = options.onReaction || (() => {});\n this.onRoomUpdate = options.onRoomUpdate || (() => {});\n this.onParticipantMediaState =\n options.onParticipantMediaState || (() => {});\n this.autoSubscribe = options.autoSubscribe !== false;\n }\n\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n\n private startHeartbeat() {\n this.stopHeartbeat();\n\n this.heartbeatTimer = setInterval(() => {\n if (this.ws?.readyState !== WebSocket.OPEN) return;\n\n this.send({\n type: \"ping\",\n payload: {\n nonce: crypto.randomUUID(),\n },\n });\n }, 10_000);\n }\n\n private stopHeartbeat() {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private createId(): string {\n return typeof crypto !== \"undefined\" && crypto.randomUUID\n ? crypto.randomUUID()\n : `id_${Math.random().toString(36).slice(2)}_${Date.now()}`;\n }\n\n private resumeStorageKey(roomCode: string) {\n return `defcomm:sfu:resume:${roomCode}`;\n }\n\n private loadResumeToken(roomCode: string): string | null {\n try {\n return localStorage.getItem(this.resumeStorageKey(roomCode));\n } catch {\n return null;\n }\n }\n\n private saveResumeToken(roomCode: string, token: string) {\n try {\n localStorage.setItem(this.resumeStorageKey(roomCode), token);\n } catch {\n // Storage can be unavailable in private/SSR environments.\n }\n }\n\n private clearResumeToken(roomCode: string | null) {\n if (!roomCode) return;\n try {\n localStorage.removeItem(this.resumeStorageKey(roomCode));\n } catch {\n // ignore\n }\n }\n\n private setState(next: SFUConnectionState) {\n if (this.state === next) return;\n this.state = next;\n this.onStateChange(next);\n }\n\n getConnectionState(): SFUConnectionState {\n return this.state;\n }\n\n getParticipantId(): string | null {\n return this.currentParticipantId;\n }\n\n getResumeToken(): string | null {\n return this.resumeToken;\n }\n\n getLocalStream(): MediaStream | null {\n return this.localStream;\n }\n\n getScreenStream(): MediaStream | null {\n return this.screenStream;\n }\n\n getRemoteScreenStream(participantId: string): MediaStream | null {\n return this.remoteScreenStreams.get(participantId) || null;\n }\n\n setLocalStream(stream: MediaStream | null) {\n this.localStream = stream;\n }\n\n private nextRequestId(): string {\n return (++this.requestId).toString();\n }\n\n private async request(url: string, options: RequestInit = {}) {\n const res = await fetch(url, {\n headers: { \"Content-Type\": \"application/json\" },\n ...options,\n });\n\n if (!res.ok) {\n let body: any = {};\n try {\n body = await res.json();\n } catch {\n // ignore non-json error bodies\n }\n throw new Error(body.message || res.statusText);\n }\n\n return res.json();\n }\n\n async createRoom(input: {\n name: string;\n description?: string;\n capacity?: number;\n is_private?: boolean;\n }) {\n return this.request(`${this.apiBase}/rooms`, {\n method: \"POST\",\n body: JSON.stringify({\n name: input.name,\n description: input.description ?? \"\",\n capacity: input.capacity ?? 20,\n is_private: input.is_private ?? false,\n }),\n });\n }\n\n async getRoom(roomCode: string) {\n return this.request(\n `${this.apiBase}/rooms/${encodeURIComponent(roomCode)}`,\n );\n }\n\n async deleteRoom(roomCode: string) {\n return this.request(\n `${this.apiBase}/rooms/${encodeURIComponent(roomCode)}`,\n {\n method: \"DELETE\",\n },\n );\n }\n\n async getToken(\n roomCode: string,\n options: {\n displayName?: string;\n avatarUrl?: string;\n participantId?: string;\n audioMuted?: boolean;\n videoMuted?: boolean;\n } = {},\n ) {\n const nextRoom = roomCode.trim();\n if (this.room && this.room !== nextRoom) {\n this.resumeToken = null;\n }\n\n this.room = nextRoom;\n this.joinOptions = {\n displayName: options.displayName,\n avatarUrl: options.avatarUrl,\n };\n if (options.participantId) this.participantId = options.participantId;\n if (typeof options.audioMuted === \"boolean\")\n this.desiredAudioMuted = options.audioMuted;\n if (typeof options.videoMuted === \"boolean\")\n this.desiredVideoMuted = options.videoMuted;\n if (!this.resumeToken) {\n this.resumeToken = this.loadResumeToken(this.room);\n }\n\n const data = await this.request(`${this.apiBase}/token`, {\n method: \"POST\",\n body: JSON.stringify({\n room_code: this.room,\n user_id: this.participantId,\n display_name: options.displayName,\n avatar_url: options.avatarUrl,\n }),\n });\n\n this.token = data?.token;\n if (!this.token) throw new Error(\"Token endpoint returned no token\");\n\n return this.connect(this.token, this.joinOptions);\n }\n\n private async refreshAccessToken() {\n if (!this.room) throw new Error(\"Cannot refresh token without a room\");\n\n const data = await this.request(`${this.apiBase}/token`, {\n method: \"POST\",\n body: JSON.stringify({\n room_code: this.room,\n user_id: this.participantId,\n display_name: this.joinOptions.displayName,\n avatar_url: this.joinOptions.avatarUrl,\n }),\n });\n\n if (!data?.token) throw new Error(\"Token refresh returned no token\");\n this.token = data.token;\n return this.token;\n }\n\n private connect(token: string, options: any = {}) {\n this.token = token;\n this.intentionalClose = false;\n this.setState(this.reconnectAttempt > 0 ? \"reconnecting\" : \"connecting\");\n\n return new Promise<void>((resolve, reject) => {\n this.joinWaiter = { resolve, reject };\n this.openWebSocket(options);\n });\n }\n\n private openWebSocket(options: any = {}) {\n if (!this.token || !this.room) {\n const error = new Error(\"Cannot connect without token and room\");\n this.failJoin(error);\n return;\n }\n\n if (this.ws) {\n try {\n this.ws.onclose = null;\n this.ws.close();\n } catch {\n // ignore\n }\n }\n\n const ws = new WebSocket(\n `${this.wsBase}?access_token=${encodeURIComponent(this.token)}`,\n );\n this.ws = ws;\n\n ws.onopen = () => {\n this.startHeartbeat();\n this.setState(\"joining\");\n this.joiningWithResume = Boolean(this.resumeToken);\n\n const joinPayload: any = {\n token: this.token,\n room_code: this.room,\n resume_token: this.resumeToken,\n display_name: options.displayName,\n avatar_url: options.avatarUrl,\n audio_muted: this.desiredAudioMuted,\n video_muted: this.desiredVideoMuted,\n };\n\n // After approval the Rust server requires the original pending request id.\n if (this.pendingJoinRequestId) {\n this.send({\n type: \"join\",\n request_id: this.pendingJoinRequestId,\n payload: joinPayload,\n });\n } else {\n this.send({ type: \"join\", payload: joinPayload });\n }\n };\n\n ws.onerror = (event) => {\n this.onError(event);\n };\n\n ws.onclose = () => {\n this.stopHeartbeat();\n if (this.ws !== ws) return;\n this.ws = null;\n\n if (this.intentionalClose || this.state === \"leaving\") {\n this.setState(\"disconnected\");\n this.onDisconnected();\n return;\n }\n\n // Keep MediaStreams and logical participant state alive.\n this.setState(\"reconnecting\");\n this.onDisconnected();\n this.scheduleReconnect();\n };\n\n ws.onmessage = async (event) => {\n if (this.ws !== ws) return;\n try {\n const message = JSON.parse(event.data);\n await this.handleServerMessage(message);\n } catch (error) {\n this.onError(error);\n }\n };\n }\n\n private scheduleReconnect() {\n if (this.reconnectTimer || this.intentionalClose) return;\n if (this.reconnectAttempt >= this.maxReconnectAttempts) {\n this.setState(\"disconnected\");\n this.failJoin(new Error(\"SFU reconnect attempts exhausted\"));\n return;\n }\n\n this.reconnectAttempt += 1;\n const delay = Math.min(\n 15000,\n this.reconnectBaseMs * Math.pow(2, this.reconnectAttempt - 1),\n );\n\n this.onReconnecting(this.reconnectAttempt);\n\n this.reconnectTimer = setTimeout(async () => {\n this.reconnectTimer = null;\n try {\n await this.refreshAccessToken();\n this.openWebSocket(this.joinOptions);\n } catch (error) {\n this.onError(error);\n this.scheduleReconnect();\n }\n }, delay);\n }\n\n private failJoin(error: any) {\n if (this.joinWaiter) {\n const waiter = this.joinWaiter;\n this.joinWaiter = null;\n waiter.reject(error);\n }\n }\n\n private resolveJoin(value: any) {\n if (!this.joinWaiter) return;\n const waiter = this.joinWaiter;\n this.joinWaiter = null;\n waiter.resolve(value);\n }\n\n private async handleServerMessage(message: any) {\n const type = message?.type;\n const payload = message?.payload || {};\n\n switch (type) {\n case \"joined\": {\n await this.handleJoined(payload);\n break;\n }\n\n case \"left\": {\n this.leaveAcknowledged = true;\n break;\n }\n\n case \"join_pending\": {\n const requestId = payload.request_id || message.request_id;\n if (!requestId) throw new Error(\"join_pending has no request_id\");\n\n this.pendingJoinRequestId = requestId;\n this.setState(\"waiting_approval\");\n this.onJoinPending({\n request_id: requestId,\n room_code: payload.room_code || this.room || undefined,\n message: payload.message,\n });\n break;\n }\n\n case \"join_approved\": {\n const requestId = payload.request_id || message.request_id;\n if (!requestId) break;\n this.pendingJoinRequestId = requestId;\n this.onJoinApproved(requestId);\n\n // Approval is a direct signal to the waiting session. Continue the join\n // with the same request id; the Rust Room layer performs the admission.\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.setState(\"joining\");\n this.send({\n type: \"join\",\n request_id: requestId,\n payload: {\n token: this.token,\n room_code: this.room,\n resume_token: this.resumeToken,\n display_name: this.joinOptions.displayName,\n avatar_url: this.joinOptions.avatarUrl,\n },\n });\n }\n break;\n }\n\n case \"join_rejected\": {\n const requestId = payload.request_id || message.request_id;\n const reason = payload.reason;\n this.onJoinRejected(requestId, reason);\n this.pendingJoinRequestId = null;\n this.intentionalClose = true;\n this.failJoin(new Error(reason || \"Join request rejected\"));\n break;\n }\n\n case \"join_requested\":\n case \"join_request\": {\n this.onJoinRequested(payload.request || payload);\n break;\n }\n\n case \"publish_answer\": {\n if (!this.publisher) break;\n await this.publisher.setRemoteDescription({\n type: \"answer\",\n sdp: payload.sdp,\n });\n await this.flushPendingIce(\"publisher\");\n break;\n }\n\n case \"subscribe_offer\": {\n this.offerQueue.push(payload);\n if (!this.subscriberNegotiating) await this.processOfferQueue();\n break;\n }\n\n case \"ice_candidate\":\n case \"publisher_ice_candidate\":\n case \"subscriber_ice_candidate\": {\n const candidatePayload = {\n ...payload,\n peer:\n payload.peer ||\n (type === \"publisher_ice_candidate\" ? \"publisher\" : \"subscriber\"),\n };\n await this.handleIce(candidatePayload);\n break;\n }\n\n case \"participant_joined\": {\n const participant = payload.participant || payload;\n const participantId =\n participant?.participant_id || payload.participant_id;\n if (!participantId || participantId === this.currentParticipantId)\n break;\n\n if (participant) this.participants.set(participantId, participant);\n this.onParticipantJoined(participant);\n break;\n }\n\n case \"participant_left\": {\n const participantId = payload.participant_id;\n if (!participantId) break;\n this.participants.delete(participantId);\n this.removeRemoteParticipant(participantId);\n this.onParticipantLeft(participantId);\n break;\n }\n\n case \"participant_media_state\": {\n const participantId = payload.participant_id;\n if (!participantId) break;\n this.onParticipantMediaState(\n participantId,\n Boolean(payload.audio_muted),\n Boolean(payload.video_muted),\n );\n break;\n }\n\n case \"participant_presence\":\n case \"participant_presence_changed\": {\n const participantId = payload.participant_id;\n const presence = payload.presence;\n if (participantId && presence) {\n this.onParticipantPresence(participantId, String(presence));\n }\n break;\n }\n\n case \"track_published\": {\n const track: TrackInfo = payload.track || payload;\n if (!track?.track_id) break;\n this.rememberTrack(track);\n\n if (track.participant_id === this.currentParticipantId) {\n if (track.source === \"audio\") {\n this.localTrackIds.set(\"audio\", track.track_id);\n const muted = !(\n this.localStream?.getAudioTracks()[0]?.enabled ?? true\n );\n this.send({\n type: \"track_state\",\n payload: { track_id: track.track_id, muted },\n });\n }\n if (track.source === \"camera\") {\n this.localTrackIds.set(\"camera\", track.track_id);\n const muted = !(\n this.localStream?.getVideoTracks()[0]?.enabled ?? true\n );\n this.send({\n type: \"track_state\",\n payload: { track_id: track.track_id, muted },\n });\n }\n if (track.source === \"screen\")\n this.localTrackIds.set(\"screen\", track.track_id);\n break;\n }\n\n this.onTrackPublished(track);\n if (this.autoSubscribe) await this.subscribe(track.track_id);\n break;\n }\n\n case \"track_unpublished\": {\n const trackId = payload.track_id || payload.track?.track_id;\n if (!trackId) break;\n const track =\n this.trackMetadata.get(trackId) ||\n ({\n track_id: trackId,\n participant_id: this.trackToParticipant.get(trackId) || \"\",\n source: this.trackToSource.get(trackId),\n kind: \"video\",\n } as TrackInfo);\n\n this.trackMetadata.delete(trackId);\n this.subscribedTracks.delete(trackId);\n this.trackToParticipant.delete(trackId);\n this.trackToSource.delete(trackId);\n\n for (const [source, localId] of this.localTrackIds) {\n if (localId === trackId) this.localTrackIds.delete(source);\n }\n\n if (track.participant_id === this.currentParticipantId) break;\n this.onTrackUnpublished(track);\n break;\n }\n\n case \"track_state_changed\": {\n const trackId = payload.track_id || payload.track?.track_id;\n if (!trackId) break;\n\n const existing = this.trackMetadata.get(trackId);\n const track: TrackInfo = {\n ...(existing || {}),\n ...(payload.track || {}),\n track_id: trackId,\n participant_id:\n payload.participant_id ||\n existing?.participant_id ||\n payload.track?.participant_id,\n kind:\n payload.kind || payload.track?.kind || existing?.kind || \"video\",\n source: payload.source || payload.track?.source || existing?.source,\n muted: Boolean(payload.muted),\n };\n\n if (!track.participant_id) break;\n this.rememberTrack(track);\n this.onTrackStateChanged(track);\n break;\n }\n\n case \"subscription_updated\": {\n // Authoritative acknowledgement of the current subscriber set.\n break;\n }\n\n case \"recording_started\": {\n this.onRecordingStarted({\n recording_id: payload.recording_id,\n started_at: payload.started_at,\n });\n break;\n }\n\n case \"recording_stopped\": {\n this.onRecordingStopped({\n recording_id: payload.recording_id,\n stopped_at: payload.stopped_at,\n });\n break;\n }\n\n case \"reconnecting\": {\n this.setState(\"reconnecting\");\n break;\n }\n\n case \"screen_share_started\": {\n const participantId = payload.participant_id;\n const track = payload.track as TrackInfo | undefined;\n if (track) this.rememberTrack(track);\n if (participantId) this.onScreenShareStarted(participantId, track);\n break;\n }\n\n case \"screen_share_stopped\": {\n const participantId = payload.participant_id;\n const trackId = payload.track_id;\n\n // Keep the underlying remote screen track alive across a logical\n // stop/start. The SFU and publisher reuse the same RTP track.\n this.onScreenShareStopped(participantId, trackId);\n break;\n }\n\n case \"room_state\": {\n const participants = payload.participants || [];\n this.onRoomStateReconciled(payload);\n this.onRoomUpdate(payload);\n for (const participant of participants) {\n const pid = participant?.participant_id;\n if (!pid) continue;\n if (pid !== this.currentParticipantId) {\n this.participants.set(pid, participant);\n this.onParticipantPresence(\n pid,\n String(participant.presence || \"connected\"),\n );\n this.onParticipantMediaState(\n pid,\n Boolean(participant.audio_muted),\n Boolean(participant.video_muted),\n );\n }\n }\n for (const [pid] of this.participants) {\n if (!participants.some((p: any) => p?.participant_id === pid)) {\n this.participants.delete(pid);\n this.removeRemoteParticipant(pid);\n this.onParticipantLeft(pid);\n }\n }\n for (const track of payload.tracks || []) this.rememberTrack(track);\n if (Array.isArray(payload.chat_history)) {\n for (const message of payload.chat_history)\n this.onChatMessage(message);\n }\n break;\n }\n\n case \"chat_message\": {\n const msg = payload.message || payload;\n if (msg?.id) this.onChatMessage(msg);\n break;\n }\n\n case \"reaction\": {\n const reaction = payload.reaction || payload;\n if (reaction?.id && reaction?.emoji) this.onReaction(reaction);\n break;\n }\n\n case \"error\": {\n const message = payload.message || \"SFU signaling error\";\n if (\n this.state === \"reconnecting\" &&\n message.includes(\"participant session is stale\")\n ) {\n console.debug(\n \"[SFU] Ignoring stale-session error during recovery\",\n message,\n );\n return;\n }\n const error = new Error(message);\n if (this.state === \"joining\" || this.state === \"waiting_approval\") {\n this.onError(error);\n this.failJoin(error);\n return;\n }\n this.onError(error);\n break;\n }\n\n default:\n console.debug(\"[SFU] Ignoring unknown server message\", message);\n }\n }\n\n private onRoomStateReconciled(payload: any) {\n const participants = payload.participants || [];\n const local = participants.find(\n (p: any) => p?.participant_id === this.currentParticipantId,\n );\n if (local) {\n this.desiredAudioMuted = Boolean(local.audio_muted);\n this.desiredVideoMuted = Boolean(local.video_muted);\n }\n }\n\n private rememberTrack(track: TrackInfo) {\n this.trackMetadata.set(track.track_id, track);\n this.trackToParticipant.set(track.track_id, track.participant_id);\n if (track.source) this.trackToSource.set(track.track_id, track.source);\n }\n\n private async handleJoined(payload: any) {\n const resumed = this.joiningWithResume;\n this.joiningWithResume = false;\n\n this.iceServers = payload.ice_servers || this.iceServers || [];\n this.currentParticipantId = payload.participant_id;\n this.resumeToken =\n payload.resume_token || payload.resumeToken || this.resumeToken;\n if (this.room && this.resumeToken) {\n this.saveResumeToken(this.room, this.resumeToken);\n }\n this.pendingJoinRequestId = null;\n this.reconnectAttempt = 0;\n\n this.participants.clear();\n this.trackMetadata.clear();\n this.trackToParticipant.clear();\n this.trackToSource.clear();\n this.localTrackIds.clear();\n\n for (const participant of payload.participants || []) {\n if (participant?.participant_id) {\n this.participants.set(participant.participant_id, participant);\n }\n }\n\n for (const track of payload.tracks || []) {\n if (track?.track_id) this.rememberTrack(track);\n }\n\n await this.initializePeerConnections();\n this.setState(\"connected\");\n this.onConnected(payload, resumed);\n\n for (const participant of this.participants.values()) {\n if (participant.participant_id !== this.currentParticipantId) {\n this.onParticipantJoined(participant);\n this.onParticipantPresence(\n participant.participant_id,\n String(participant.presence || \"connected\"),\n );\n this.onParticipantMediaState(\n participant.participant_id,\n Boolean(participant.audio_muted),\n Boolean(participant.video_muted),\n );\n }\n }\n\n if (Array.isArray(payload.chat_history)) {\n for (const message of payload.chat_history) this.onChatMessage(message);\n }\n this.onRoomUpdate(payload);\n\n // A reconnect/resume needs a fresh publisher negotiation and subscription\n // reconciliation because the WebSocket transport was replaced.\n if (this.localStream) {\n await this.publishExistingTracks();\n }\n\n if (this.autoSubscribe) {\n const trackIds = [...this.trackMetadata.values()]\n .filter((track) => track.participant_id !== this.currentParticipantId)\n .map((track) => track.track_id);\n if (trackIds.length) await this.subscribeMultiple(trackIds);\n }\n\n this.resolveJoin(payload);\n }\n\n private async initializePeerConnections() {\n this.closePeerConnectionsOnly();\n this.publisherRevision = 0;\n\n const config: RTCConfiguration = { iceServers: this.iceServers };\n this.publisher = new RTCPeerConnection(config);\n this.subscriber = new RTCPeerConnection(config);\n\n // Keep audio, camera, and screen on three permanent publisher m-lines.\n // This mirrors the working client: screen sharing must never reuse the\n // camera sender/transceiver.\n this.audioTransceiver = this.publisher.addTransceiver(\"audio\", {\n direction: \"sendonly\",\n });\n this.cameraTransceiver = this.publisher.addTransceiver(\"video\", {\n direction: \"sendonly\",\n });\n this.screenTransceiver = this.publisher.addTransceiver(\"video\", {\n direction: \"inactive\",\n });\n\n this.audioSender = this.audioTransceiver.sender;\n this.videoSender = this.cameraTransceiver.sender;\n this.screenSender = this.screenTransceiver.sender;\n\n this.publisher.onicecandidate = (event) => {\n if (event.candidate) this.sendCandidate(\"publisher\", event.candidate);\n };\n\n this.subscriber.onicecandidate = (event) => {\n if (event.candidate) this.sendCandidate(\"subscriber\", event.candidate);\n };\n\n this.publisher.onconnectionstatechange = () => {\n const publisher = this.publisher;\n if (!publisher) return;\n\n const state = publisher.connectionState;\n\n console.debug(\"[SFU] Publisher connection state\", {\n connectionState: publisher.connectionState,\n iceConnectionState: publisher.iceConnectionState,\n iceGatheringState: publisher.iceGatheringState,\n signalingState: publisher.signalingState,\n });\n\n if (state === \"failed\") {\n this.recoverWebRTC(\"publisher_failed\");\n }\n };\n\n this.subscriber.onconnectionstatechange = () => {\n const subscriber = this.subscriber;\n if (!subscriber) return;\n\n const state = subscriber.connectionState;\n\n console.debug(\"[SFU] Subscriber connection state\", {\n connectionState: subscriber.connectionState,\n iceConnectionState: subscriber.iceConnectionState,\n iceGatheringState: subscriber.iceGatheringState,\n signalingState: subscriber.signalingState,\n });\n\n if (state === \"failed\") {\n this.recoverWebRTC(\"subscriber_failed\");\n }\n };\n this.publisher.oniceconnectionstatechange = () => {\n const publisher = this.publisher;\n if (!publisher) return;\n\n console.debug(\"[SFU] Publisher ICE state\", {\n iceConnectionState: publisher.iceConnectionState,\n connectionState: publisher.connectionState,\n });\n };\n\n this.subscriber.oniceconnectionstatechange = () => {\n const subscriber = this.subscriber;\n if (!subscriber) return;\n\n console.debug(\"[SFU] Subscriber ICE state\", {\n iceConnectionState: subscriber.iceConnectionState,\n connectionState: subscriber.connectionState,\n });\n };\n\n this.subscriber.ontrack = (event) => {\n void this.handleRemoteTrack(event);\n };\n\n if (!this.subscriberStatsTimer) {\n this.subscriberStatsTimer = setInterval(() => {\n void this.logSubscriberVideoStats();\n }, 3000);\n }\n }\n\n private async handleRemoteTrack(event: RTCTrackEvent) {\n const stream = event.streams?.[0] || null;\n const metadata = this.resolveRemoteTrackMetadata(event.track, stream);\n\n if (!metadata?.participant_id) {\n this.onError(\n new Error(\n `Remote ${event.track.kind} track ${event.track.id} has no SFU participant mapping`,\n ),\n );\n return;\n }\n\n const participantId = metadata.participant_id;\n const source = String(\n metadata.source || this.trackToSource.get(metadata.track_id) || \"\",\n )\n .trim()\n .toLowerCase();\n\n // Screen is a completely separate media path. Never put it in the\n // participant's normal camera/audio MediaStream.\n if (source === \"screen\" || source === \"screen_share\") {\n let screenStream = this.remoteScreenStreams.get(participantId);\n\n if (!screenStream) {\n screenStream = new MediaStream();\n this.remoteScreenStreams.set(participantId, screenStream);\n }\n\n for (const existing of screenStream.getVideoTracks()) {\n if (existing.id !== event.track.id) {\n screenStream.removeTrack(existing);\n existing.stop();\n }\n }\n\n if (\n !screenStream.getTracks().some((track) => track.id === event.track.id)\n ) {\n screenStream.addTrack(event.track);\n }\n\n event.track.onended = () => {\n try {\n screenStream?.removeTrack(event.track);\n } catch {}\n\n if (screenStream?.getTracks().length === 0) {\n this.remoteScreenStreams.delete(participantId);\n this.onScreenShareStopped(participantId, metadata.track_id);\n }\n };\n\n this.onScreenShareStarted(participantId, metadata);\n this.onRemoteTrack(event.track, screenStream, {\n ...metadata,\n source: \"screen\",\n });\n return;\n }\n\n // Only audio and camera video belong to the normal participant stream.\n if (event.track.kind === \"video\" && source !== \"camera\") {\n this.onError(\n new Error(\n `Refusing to route unknown remote video source to camera: ${metadata.track_id}`,\n ),\n );\n return;\n }\n\n let remoteStream = this.remoteStreams.get(participantId);\n if (!remoteStream) {\n remoteStream = new MediaStream();\n this.remoteStreams.set(participantId, remoteStream);\n }\n\n for (const existing of remoteStream.getTracks()) {\n if (\n existing.kind === event.track.kind &&\n existing.id !== event.track.id\n ) {\n remoteStream.removeTrack(existing);\n existing.stop();\n }\n }\n\n if (\n !remoteStream.getTracks().some((track) => track.id === event.track.id)\n ) {\n remoteStream.addTrack(event.track);\n }\n\n event.track.onended = () => {\n try {\n remoteStream?.removeTrack(event.track);\n } catch {}\n };\n\n this.onRemoteTrack(event.track, remoteStream, {\n ...metadata,\n source: event.track.kind === \"audio\" ? \"audio\" : \"camera\",\n });\n }\n\n private normalizeRemoteTrackId(browserTrackId: string): string {\n return browserTrackId?.startsWith(\"track-\")\n ? browserTrackId.slice(\"track-\".length)\n : browserTrackId;\n }\n\n private resolveRemoteTrackMetadata(\n track: MediaStreamTrack,\n stream: MediaStream | null,\n ): TrackInfo | null {\n const candidates = [\n this.normalizeRemoteTrackId(track.id),\n track.id,\n stream?.id ? this.normalizeRemoteTrackId(stream.id) : null,\n stream?.id || null,\n ].filter(Boolean) as string[];\n\n for (const id of candidates) {\n const metadata = this.trackMetadata.get(id);\n if (metadata) return metadata;\n }\n\n // Never guess by participant + kind. A participant can publish camera\n // and screen simultaneously; guessing is exactly how a screen track can\n // end up in the camera tile.\n return null;\n }\n\n private sendCandidate(peer: PeerName, candidate: RTCIceCandidate) {\n this.send({\n type: \"ice_candidate\",\n payload: {\n peer,\n candidate: candidate.candidate,\n sdp_mid: candidate.sdpMid,\n sdp_mline_index: candidate.sdpMLineIndex,\n username_fragment: candidate.usernameFragment,\n },\n });\n }\n\n private async handleIce(payload: any) {\n const peer: PeerName =\n payload.peer === \"publisher\" ? \"publisher\" : \"subscriber\";\n const pc = peer === \"publisher\" ? this.publisher : this.subscriber;\n\n const candidate: RTCIceCandidateInit = {\n candidate: payload.candidate,\n sdpMid: payload.sdp_mid ?? payload.sdpMid ?? null,\n sdpMLineIndex: payload.sdp_mline_index ?? payload.sdpMLineIndex ?? null,\n usernameFragment:\n payload.username_fragment ?? payload.usernameFragment ?? null,\n };\n\n if (!pc || !pc.remoteDescription) {\n this.pendingIce[peer].push(candidate);\n return;\n }\n\n try {\n await pc.addIceCandidate(candidate);\n } catch (error) {\n this.onError(\n new Error(`Failed to add ${peer} ICE candidate: ${String(error)}`),\n );\n }\n }\n\n private async flushPendingIce(peer: PeerName) {\n const pc = peer === \"publisher\" ? this.publisher : this.subscriber;\n if (!pc || !pc.remoteDescription) return;\n\n const queue = this.pendingIce[peer];\n while (queue.length) {\n const candidate = queue.shift()!;\n try {\n await pc.addIceCandidate(candidate);\n } catch (error) {\n this.onError(\n new Error(\n `Failed to add queued ${peer} ICE candidate: ${String(error)}`,\n ),\n );\n }\n }\n }\n\n private async processOfferQueue() {\n if (!this.subscriber) return;\n\n while (this.offerQueue.length) {\n if (this.subscriberNegotiating) return;\n this.subscriberNegotiating = true;\n const offer = this.offerQueue.shift();\n\n try {\n await this.subscriber.setRemoteDescription({\n type: \"offer\",\n sdp: offer.sdp,\n });\n await this.flushPendingIce(\"subscriber\");\n\n const answer = await this.subscriber.createAnswer();\n await this.subscriber.setLocalDescription(answer);\n\n this.send({\n type: \"subscribe_answer\",\n payload: {\n revision: offer.revision,\n sdp: answer.sdp,\n },\n });\n\n // One subscribe request produces one subscriber offer. Resolve only\n // the waiter belonging to this offer; resolving the entire queue can\n // make later subscribe calls look complete before they were negotiated.\n const waiter = this.subscriptionWaiters.shift();\n waiter?.resolve();\n } catch (error) {\n const waiter = this.subscriptionWaiters.shift();\n if (waiter) {\n waiter.trackIds.forEach((id) => this.subscribedTracks.delete(id));\n waiter.reject(error);\n }\n this.onError(\n new Error(`Failed to process subscriber offer: ${String(error)}`),\n );\n } finally {\n this.subscriberNegotiating = false;\n }\n }\n }\n\n private async subscribe(trackId: string) {\n if (!trackId || this.subscribedTracks.has(trackId)) return;\n this.subscribedTracks.add(trackId);\n this.subscriptionQueue.push(trackId);\n if (!this.subscriptionRunning) await this.processSubscriptionQueue();\n }\n\n private async subscribeMultiple(trackIds: string[]) {\n const uniqueIds = [...new Set(trackIds.filter(Boolean))].filter(\n (id) => !this.subscribedTracks.has(id),\n );\n if (!uniqueIds.length || !this.isSocketOpen()) return;\n\n uniqueIds.forEach((id) => this.subscribedTracks.add(id));\n return new Promise<void>((resolve, reject) => {\n const sent = this.send({\n type: \"subscribe\",\n payload: { track_ids: uniqueIds },\n });\n\n if (!sent) {\n uniqueIds.forEach((id) => this.subscribedTracks.delete(id));\n reject(new Error(\"Signaling socket is not open\"));\n return;\n }\n\n this.subscriptionWaiters.push({\n trackIds: uniqueIds,\n resolve,\n reject,\n });\n });\n }\n\n private async processSubscriptionQueue() {\n this.subscriptionRunning = true;\n try {\n while (this.subscriptionQueue.length) {\n const trackId = this.subscriptionQueue.shift()!;\n if (!this.isSocketOpen()) {\n this.subscribedTracks.delete(trackId);\n continue;\n }\n\n await new Promise<void>((resolve, reject) => {\n const sent = this.send({\n type: \"subscribe\",\n payload: { track_ids: [trackId] },\n });\n\n if (!sent) {\n this.subscribedTracks.delete(trackId);\n reject(new Error(\"Signaling socket is not open\"));\n return;\n }\n\n this.subscriptionWaiters.push({\n trackIds: [trackId],\n resolve,\n reject,\n });\n });\n }\n } finally {\n this.subscriptionRunning = false;\n }\n }\n\n async publish({ audio = true, video = true } = {}) {\n if (!this.publisher)\n throw new Error(\"Publisher PeerConnection is not initialized\");\n\n if (!this.localStream) {\n this.localStream = await navigator.mediaDevices.getUserMedia({\n audio,\n video,\n });\n }\n\n await this.publishExistingTracks(audio, video);\n return this.localStream;\n }\n\n private async publishExistingTracks(audio = true, video = true) {\n if (!this.publisher || !this.localStream) return;\n\n if (\n !this.audioTransceiver ||\n !this.cameraTransceiver ||\n !this.screenTransceiver\n ) {\n throw new Error(\"Publisher transceivers are not initialized\");\n }\n\n const audioTrack = this.localStream\n .getAudioTracks()\n .find((track) => track.readyState === \"live\");\n const cameraTrack = this.localStream\n .getVideoTracks()\n .find((track) => track.readyState === \"live\");\n const screenTrack = this.screenStream\n ?.getVideoTracks()\n .find((track) => track.readyState === \"live\");\n\n await this.audioSender?.replaceTrack(\n audio && audioTrack ? audioTrack : null,\n );\n this.audioTransceiver.direction =\n audio && audioTrack ? \"sendonly\" : \"inactive\";\n\n await this.videoSender?.replaceTrack(\n video && cameraTrack ? cameraTrack : null,\n );\n this.cameraTransceiver.direction =\n video && cameraTrack ? \"sendonly\" : \"inactive\";\n\n await this.screenSender?.replaceTrack(screenTrack || null);\n this.screenTransceiver.direction = screenTrack ? \"sendonly\" : \"inactive\";\n\n if (!audioTrack && !cameraTrack && !screenTrack) return;\n\n const offer = await this.publisher.createOffer();\n await this.publisher.setLocalDescription(offer);\n\n this.send({\n type: \"publish_offer\",\n payload: {\n revision: ++this.publisherRevision,\n sdp: offer.sdp,\n },\n });\n\n if (screenTrack) {\n this.send({ type: \"start_screen_share\" });\n }\n }\n\n async shareScreen() {\n if (!this.publisher) {\n throw new Error(\"Publisher PeerConnection is not initialized\");\n }\n\n if (!this.screenTransceiver || !this.screenSender) {\n throw new Error(\"Screen transceiver is not initialized\");\n }\n\n const existing = this.screenStream;\n const existingTrack = this.screenSender.track;\n\n // Already sharing.\n if (existing || (existingTrack && existingTrack.readyState === \"live\")) {\n return existing;\n }\n\n try {\n await this.screenSender.replaceTrack(null);\n } catch {}\n\n this.screenTransceiver.direction = \"inactive\";\n\n const screenStream = await navigator.mediaDevices.getDisplayMedia({\n video: true,\n audio: false,\n });\n\n const screenTrack = screenStream.getVideoTracks()[0];\n\n if (!screenTrack) {\n screenStream.getTracks().forEach((track) => track.stop());\n throw new Error(\"Screen share returned no video track\");\n }\n\n const generation = ++this.screenShareGeneration;\n\n this.screenStream = screenStream;\n\n try {\n await this.screenSender.replaceTrack(screenTrack);\n\n this.screenTransceiver.direction = \"sendonly\";\n\n this.send({\n type: \"start_screen_share\",\n });\n\n const offer = await this.publisher.createOffer();\n\n await this.publisher.setLocalDescription(offer);\n\n const localDescription = this.publisher.localDescription;\n\n if (!localDescription?.sdp) {\n throw new Error(\"Publisher did not produce a valid screen-share SDP\");\n }\n\n this.send({\n type: \"publish_offer\",\n payload: {\n revision: ++this.publisherRevision,\n sdp: localDescription.sdp,\n },\n });\n\n screenTrack.onended = () => {\n if (generation !== this.screenShareGeneration) {\n return;\n }\n\n void this.stopScreenShare();\n };\n\n return this.screenStream;\n } catch (error) {\n try {\n await this.screenSender.replaceTrack(null);\n } catch {}\n\n this.screenTransceiver.direction = \"inactive\";\n\n screenTrack.onended = null;\n\n screenStream.getTracks().forEach((track) => {\n try {\n track.stop();\n } catch {}\n });\n\n this.screenStream = null;\n\n try {\n this.send({\n type: \"stop_screen_share\",\n });\n } catch {}\n\n throw error;\n }\n }\n\n async stopScreenShare() {\n const stream = this.screenStream;\n const senderTrack = this.screenSender?.track || null;\n\n if (!stream && !senderTrack) {\n return;\n }\n\n ++this.screenShareGeneration;\n\n if (senderTrack) {\n senderTrack.onended = null;\n }\n\n try {\n await this.screenSender?.replaceTrack(null);\n } catch (error) {\n this.onError(error);\n }\n\n if (this.screenTransceiver) {\n this.screenTransceiver.direction = \"inactive\";\n }\n\n try {\n if (this.publisher) {\n const offer = await this.publisher.createOffer();\n\n await this.publisher.setLocalDescription(offer);\n\n const localDescription = this.publisher.localDescription;\n\n if (localDescription?.sdp) {\n this.send({\n type: \"publish_offer\",\n payload: {\n revision: ++this.publisherRevision,\n sdp: localDescription.sdp,\n },\n });\n }\n }\n } catch (error) {\n this.onError(error);\n }\n\n this.send({\n type: \"stop_screen_share\",\n });\n\n stream?.getTracks().forEach((track) => {\n try {\n track.stop();\n } catch {}\n });\n\n this.screenStream = null;\n\n if (this.currentParticipantId) {\n this.onScreenShareStopped(this.currentParticipantId);\n }\n }\n\n muteAudio(muted: boolean) {\n this.desiredAudioMuted = muted;\n this.localStream?.getAudioTracks().forEach((track) => {\n track.enabled = !muted;\n });\n\n this.send({\n type: \"set_media_state\",\n payload: { audio_muted: muted, video_muted: this.desiredVideoMuted },\n });\n\n const trackId = this.localTrackIds.get(\"audio\");\n if (trackId) {\n this.send({\n type: \"track_state\",\n payload: {\n track_id: trackId,\n muted,\n },\n });\n }\n }\n\n muteVideo(muted: boolean) {\n this.desiredVideoMuted = muted;\n this.localStream?.getVideoTracks().forEach((track) => {\n track.enabled = !muted;\n });\n\n this.send({\n type: \"set_media_state\",\n payload: { audio_muted: this.desiredAudioMuted, video_muted: muted },\n });\n\n const trackId = this.localTrackIds.get(\"camera\");\n if (trackId) {\n this.send({\n type: \"track_state\",\n payload: {\n track_id: trackId,\n muted,\n },\n });\n }\n }\n\n sendChatMessage(input: {\n message: string;\n reply_to?: any;\n target?: string | null;\n }) {\n return this.send({\n type: \"send_chat\",\n payload: {\n message: input.message,\n reply_to: input.reply_to ?? null,\n target: input.target ?? null,\n },\n });\n }\n\n async startRecording() {\n if (!this.send({ type: \"start_recording\" })) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n async stopRecording() {\n if (!this.send({ type: \"stop_recording\" })) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n async getRecordingStatus() {\n if (!this.room || !this.token) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.request(\n `${this.apiBase}/rooms/${encodeURIComponent(this.room)}/recording`,\n {\n headers: {\n Authorization: `Bearer ${this.token}`,\n },\n },\n );\n }\n\n async approveJoinRequest(requestId: string) {\n if (!requestId) throw new Error(\"requestId is required\");\n if (\n !this.send({ type: \"approve_join\", payload: { request_id: requestId } })\n ) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n async rejectJoinRequest(requestId: string, reason?: string) {\n if (!requestId) throw new Error(\"requestId is required\");\n if (\n !this.send({\n type: \"reject_join\",\n payload: { request_id: requestId, reason },\n })\n ) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n private isSocketOpen() {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n private send(message: any) {\n if (!this.isSocketOpen()) return false;\n this.ws!.send(\n JSON.stringify({\n request_id: this.nextRequestId(),\n ...message,\n }),\n );\n return true;\n }\n\n sendReaction(reaction: string): void {\n this.send({\n type: \"send_reaction\",\n payload: {\n emoji: reaction,\n },\n });\n }\n\n private removeRemoteParticipant(participantId: string) {\n const stream = this.remoteStreams.get(participantId);\n if (stream) {\n stream.getTracks().forEach((track) => track.stop());\n this.remoteStreams.delete(participantId);\n }\n\n const screenStream = this.remoteScreenStreams.get(participantId);\n if (screenStream) {\n screenStream.getTracks().forEach((track) => track.stop());\n this.remoteScreenStreams.delete(participantId);\n }\n\n for (const [trackId, metadata] of this.trackMetadata) {\n if (metadata.participant_id === participantId) {\n this.trackMetadata.delete(trackId);\n this.subscribedTracks.delete(trackId);\n this.trackToParticipant.delete(trackId);\n this.trackToSource.delete(trackId);\n }\n }\n }\n\n async leave() {\n this.stopHeartbeat();\n this.intentionalClose = true;\n this.setState(\"leaving\");\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n const roomCode = this.room;\n const ws = this.ws;\n this.leaveAcknowledged = false;\n\n if (ws?.readyState === WebSocket.OPEN) {\n await new Promise<void>((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n resolve();\n };\n\n // The normal onmessage path remains authoritative. We only wait for\n // the server's `left` acknowledgement through a short polling window.\n const timeout = setTimeout(finish, 1200);\n\n const check = () => {\n if (this.leaveAcknowledged || this.ws !== ws) {\n clearTimeout(timeout);\n finish();\n return;\n }\n if (ws.readyState !== WebSocket.OPEN) {\n clearTimeout(timeout);\n finish();\n return;\n }\n setTimeout(check, 25);\n };\n\n ws.addEventListener(\n \"close\",\n () => {\n clearTimeout(timeout);\n finish();\n },\n { once: true },\n );\n\n this.send({ type: \"leave\" });\n check();\n });\n\n try {\n ws.close(1000, \"client_leave\");\n } catch {\n // ignore\n }\n }\n\n this.clearResumeToken(roomCode);\n this.cleanupAll();\n this.setState(\"disconnected\");\n }\n\n private closePeerConnectionsOnly() {\n if (this.publisher) {\n try {\n this.publisher.close();\n } catch {\n /* ignore */\n }\n this.publisher = null;\n }\n if (this.subscriber) {\n try {\n this.subscriber.close();\n } catch {\n /* ignore */\n }\n this.subscriber = null;\n }\n this.videoSender = null;\n this.audioSender = null;\n this.screenSender = null;\n this.audioTransceiver = null;\n this.cameraTransceiver = null;\n this.screenTransceiver = null;\n this.pendingIce = { publisher: [], subscriber: [] };\n this.offerQueue = [];\n this.subscriberNegotiating = false;\n this.subscriptionQueue = [];\n this.subscriptionRunning = false;\n this.subscriptionWaiters\n .splice(0)\n .forEach((w) => w.reject(new Error(\"PeerConnection recreated\")));\n this.subscribedTracks.clear();\n }\n\n private cleanupAll() {\n if (this.subscriberStatsTimer) {\n clearInterval(this.subscriberStatsTimer);\n this.subscriberStatsTimer = null;\n }\n\n this.closePeerConnectionsOnly();\n\n this.localStream?.getTracks().forEach((track) => track.stop());\n this.screenStream?.getTracks().forEach((track) => track.stop());\n this.localStream = null;\n this.screenStream = null;\n\n for (const stream of this.remoteStreams.values()) {\n stream.getTracks().forEach((track) => track.stop());\n }\n this.remoteStreams.clear();\n\n for (const stream of this.remoteScreenStreams.values()) {\n stream.getTracks().forEach((track) => track.stop());\n }\n this.remoteScreenStreams.clear();\n\n this.trackMetadata.clear();\n this.trackToParticipant.clear();\n this.trackToSource.clear();\n this.localTrackIds.clear();\n this.participants.clear();\n this.currentParticipantId = null;\n this.resumeToken = null;\n this.pendingJoinRequestId = null;\n this.token = null;\n this.room = null;\n\n if (this.ws) {\n try {\n this.ws.close();\n } catch {\n /* ignore */\n }\n this.ws = null;\n }\n }\n\n private async logSubscriberVideoStats() {\n if (!this.subscriber || this.subscriber.connectionState === \"closed\")\n return;\n try {\n const stats = await this.subscriber.getStats();\n stats.forEach((report: any) => {\n if (\n report.type === \"inbound-rtp\" &&\n (report.kind === \"video\" || report.mediaType === \"video\")\n ) {\n console.debug(\"[SFU] subscriber video\", {\n packetsReceived: report.packetsReceived,\n packetsLost: report.packetsLost,\n framesDecoded: report.framesDecoded,\n frameWidth: report.frameWidth,\n frameHeight: report.frameHeight,\n });\n }\n });\n } catch {\n // stats are diagnostic only\n }\n }\n\n private recoverWebRTC(reason: string) {\n if (this.intentionalClose) return;\n\n if (this.transportRecoveryInProgress) {\n console.debug(\"[SFU] WebRTC recovery already in progress\", {\n reason,\n });\n return;\n }\n\n this.transportRecoveryInProgress = true;\n\n console.warn(\"[SFU] WebRTC transport failed; starting recovery\", {\n reason,\n publisherState: this.publisher?.connectionState,\n publisherIceState: this.publisher?.iceConnectionState,\n subscriberState: this.subscriber?.connectionState,\n subscriberIceState: this.subscriber?.iceConnectionState,\n });\n\n this.setState(\"reconnecting\");\n\n this.transportRecoveryTimer = setTimeout(() => {\n this.transportRecoveryTimer = null;\n\n if (this.intentionalClose) {\n this.transportRecoveryInProgress = false;\n return;\n }\n\n const ws = this.ws;\n\n if (ws && ws.readyState === WebSocket.OPEN) {\n try {\n ws.close(4000, \"webrtc_recovery\");\n } catch (error) {\n console.warn(\"[SFU] Failed to close WebSocket for recovery\", error);\n\n this.transportRecoveryInProgress = false;\n this.scheduleReconnect();\n }\n\n return;\n }\n\n this.transportRecoveryInProgress = false;\n this.scheduleReconnect();\n }, 250);\n }\n}\n","import { SDK_CONFIG } from \"../config/ws\";\nimport {\n ChatInput,\n ChatMessage,\n Reaction,\n Events,\n MeetingConfig,\n SDKError,\n RecordingInfo,\n VideoSDKCoreOptions,\n} from \"../types/meeting\";\nimport { ActiveSpeakerDetector } from \"./ActiveSpeakerDetector\";\nimport { MeetingState } from \"./MeetingState\";\nimport { SFUClient, SFUConnectionState, TrackInfo } from \"./SFUClient\";\n\nexport class VideoSDKCore {\n private sfuClient: SFUClient | null = null;\n private myId: string;\n private room: {\n id: string | null;\n name: string | null;\n } = {\n id: null,\n name: null,\n };\n private localStream: MediaStream | null = null;\n private screenStream: MediaStream | null = null;\n private isScreenSharing = false;\n private participantName = \"\";\n\n public readonly state: MeetingState;\n\n private intentionalDisconnect = false;\n\n private remoteStreams = new Map<string, MediaStream>();\n private remoteScreenStreams = new Map<string, MediaStream>();\n\n private activeSpeakerDetector: ActiveSpeakerDetector;\n\n private joinPromise: Promise<void> | null = null;\n private disconnectPromise: Promise<void> | null = null;\n\n private emitError(\n code: string,\n message: string,\n raw?: any,\n recoverable = true,\n ) {\n const err: SDKError = {\n code,\n message,\n raw,\n roomId: this.room.id,\n participantId: this.myId,\n recoverable,\n };\n\n this.events.onError?.(err);\n\n console.error(\"[MeetingSDK Error]\", err);\n }\n\n constructor(\n options: VideoSDKCoreOptions,\n private events: Events = {},\n private apiBase: string = SDK_CONFIG.apiBase,\n private wsBase: string = SDK_CONFIG.wsBase,\n ) {\n this.state = new MeetingState();\n this.events = events;\n this.activeSpeakerDetector = new ActiveSpeakerDetector({\n onActiveSpeakersChanged: (participantIds) => {\n this.state.setActiveSpeakers(participantIds);\n\n this.events.onActiveSpeakersChanged?.(participantIds);\n },\n });\n this.myId = options.participantId;\n }\n\n // LOCAL MEDIA\n\n async initLocal(video: HTMLVideoElement, name: string) {\n this.participantName = name;\n\n try {\n this.localStream = await navigator.mediaDevices.getUserMedia({\n video: {\n width: { ideal: 1280 },\n height: { ideal: 720 },\n },\n audio: {\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n },\n });\n\n const localAudioTrack = this.localStream.getAudioTracks()[0];\n\n if (localAudioTrack) {\n this.activeSpeakerDetector.addTrack(this.myId, localAudioTrack);\n }\n\n const hasVideo = this.localStream\n .getVideoTracks()\n .some((t) => t.readyState === \"live\");\n\n const hasAudio = this.localStream\n .getAudioTracks()\n .some((t) => t.readyState === \"live\");\n\n if (!hasVideo || !hasAudio) {\n throw new Error(`Missing tracks: video=${hasVideo}, audio=${hasAudio}`);\n }\n\n video.srcObject = this.localStream;\n\n this.updateLocalMedia();\n } catch (err: any) {\n this.emitError(\"GET_USER_MEDIA_FAILED\", err?.message, err, false);\n\n throw err;\n }\n }\n\n private updateLocalMedia(audioMuted = false, videoMuted = false) {\n if (!this.localStream) return;\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n\n media: {\n stream: this.localStream,\n cameraTrack: this.localStream.getVideoTracks()[0],\n audioTrack: this.localStream.getAudioTracks()[0],\n micEnabled:\n this.localStream.getAudioTracks()[0]?.enabled ?? !audioMuted,\n camEnabled:\n this.localStream.getVideoTracks()[0]?.enabled ?? !videoMuted,\n isScreenSharing: this.isScreenSharing,\n screenStream: this.screenStream,\n screenTrack: this.screenStream?.getVideoTracks()[0],\n },\n });\n\n this.state.localStream = this.localStream;\n }\n\n // ROOM MANAGEMENT\n async createRoom(input: {\n name: string;\n description?: string;\n capacity?: number;\n is_private?: boolean;\n }) {\n const client =\n this.sfuClient ??\n new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n participantId: this.myId,\n });\n\n return client.createRoom(input);\n }\n\n async getRoom(roomCode: string) {\n const client =\n this.sfuClient ??\n new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n participantId: this.myId,\n });\n\n return client.getRoom(roomCode);\n }\n\n async deleteRoom(roomCode: string) {\n const client =\n this.sfuClient ??\n new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n participantId: this.myId,\n });\n\n return client.deleteRoom(roomCode);\n }\n\n // JOIN\n async joinMeeting(\n config: Omit<MeetingConfig, \"participantId\">,\n ): Promise<void> {\n const { roomId, name, audioMuted = false, videoMuted = false } = config;\n\n if (!roomId || !name) {\n throw new Error(\"roomId and name are required to join meeting\");\n }\n\n if (!this.myId) {\n throw new Error(\"participantId is required\");\n }\n\n /*Already connected?\n * Calling join() again must NOT cause leave().\n */\n if (\n this.sfuClient &&\n this.room.id === roomId &&\n this.sfuClient.getConnectionState() === \"connected\"\n ) {\n console.info(\"[SDK] Already connected; duplicate join ignored\", {\n roomId,\n participantId: this.myId,\n });\n\n return;\n }\n\n if (this.joinPromise) {\n console.info(\n \"[SDK] Join already in progress; waiting for existing join\",\n {\n roomId,\n participantId: this.myId,\n },\n );\n\n return this.joinPromise;\n }\n\n if (this.sfuClient && this.room.id && this.room.id !== roomId) {\n throw new Error(\n `Already connected to room ${this.room.id}. Leave the current meeting before joining another room.`,\n );\n }\n\n this.intentionalDisconnect = false;\n this.participantName = name;\n this.room.id = roomId;\n this.room.name = name;\n\n if (!this.localStream) {\n this.localStream = await navigator.mediaDevices.getUserMedia({\n video: true,\n audio: true,\n });\n\n const localAudioTrack = this.localStream.getAudioTracks()[0];\n\n if (localAudioTrack) {\n this.activeSpeakerDetector.addTrack(this.myId, localAudioTrack);\n }\n }\n\n this.localStream.getAudioTracks().forEach((track) => {\n track.enabled = !audioMuted;\n });\n\n this.localStream.getVideoTracks().forEach((track) => {\n track.enabled = !videoMuted;\n });\n\n this.updateLocalMedia(audioMuted, videoMuted);\n\n const promise = this.connect(roomId, name);\n\n this.joinPromise = promise;\n\n try {\n await promise;\n } finally {\n if (this.joinPromise === promise) {\n this.joinPromise = null;\n }\n }\n }\n\n // SFU CONNECTION\n private async connect(roomId: string, name: string): Promise<void> {\n if (this.sfuClient) {\n const state = this.sfuClient.getConnectionState();\n if (\n this.room.id === roomId &&\n (state === \"connecting\" ||\n state === \"connected\" ||\n state === \"reconnecting\")\n ) {\n console.info(\n \"[SDK] Existing SFU connection is active; connect ignored\",\n {\n roomId,\n state,\n },\n );\n\n return;\n }\n\n throw new Error(\n `SFU client already exists in state \"${state}\". Disconnect explicitly before creating another connection.`,\n );\n }\n\n const client = new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n participantId: this.myId,\n autoSubscribe: true,\n // CONNECTION STATE\n\n onStateChange: (state) => {\n this.handleSFUState(state);\n },\n\n onConnected: (payload, resumed) => {\n console.log(`[SFU] ${resumed ? \"Resumed\" : \"Joined\"} room`, payload);\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n });\n },\n\n onDisconnected: () => {\n /*\n * Disconnected does NOT necessarily mean\n * the participant left the room.\n * SFUClient should attempt reconnect.\n */\n console.log(\"[SFU] Signaling WebSocket disconnected; reconnecting\");\n },\n\n onReconnecting: (attempt) => {\n console.warn(`[SFU] Reconnecting, attempt ${attempt}`);\n },\n\n // ADMISSION CONTROL\n onRoomUpdate: (payload) => {\n const participants = payload?.participants || [];\n const local = participants.find(\n (p: any) => p?.participant_id === this.myId,\n );\n if (local) {\n const media = this.state.localParticipant?.media;\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n media: {\n micEnabled: !Boolean(local.audio_muted),\n camEnabled: !Boolean(local.video_muted),\n isScreenSharing: Boolean(local.screen_sharing),\n screenStream: this.screenStream,\n screenTrack: this.screenStream?.getVideoTracks()[0],\n },\n });\n if (this.localStream) {\n this.localStream.getAudioTracks().forEach((track) => {\n track.enabled = !Boolean(local.audio_muted);\n });\n this.localStream.getVideoTracks().forEach((track) => {\n track.enabled = !Boolean(local.video_muted);\n });\n }\n if (local.screen_sharing) this.state.setPresenterId(this.myId);\n else if (this.state.presenterId === this.myId)\n this.state.setPresenterId(null);\n }\n const presenter = participants.find((p: any) => p?.screen_sharing);\n if (presenter) this.state.setPresenterId(presenter.participant_id);\n else if (!local?.screen_sharing) this.state.setPresenterId(null);\n for (const message of payload?.chat_history || []) {\n this.state.addChatMessage(message);\n }\n this.events.onRoomUpdate?.(payload);\n },\n\n onJoinPending: (info) => {\n // This is the LOCAL participant waiting for host approval. It is not\n // an incoming admission request for the host/moderator UI. Never\n // publish it through onEntryRequested, otherwise the waiting client\n // can render and attempt to approve its own request after reconnect.\n console.log(\"[SFU] Join request pending\", info);\n },\n\n onJoinApproved: (requestId) => {\n console.log(\"[SFU] Join approved\", requestId);\n this.events.onJoinApproved?.(requestId);\n this.events.onEntryResponded?.(\n {\n participantId: this.myId,\n decision: \"approved\",\n },\n\n \"approved\",\n );\n },\n\n onJoinRejected: (requestId, reason) => {\n console.warn(\"[SFU] Join rejected\", requestId, reason);\n this.events.onJoinRejected?.(requestId);\n this.events.onEntryResponded?.(\n {\n participantId: this.myId,\n decision: \"rejected\",\n },\n\n \"rejected\",\n );\n\n this.emitError(\n \"JOIN_REJECTED\",\n reason || \"Your request to join was rejected\",\n {\n requestId,\n reason,\n },\n false,\n );\n },\n\n onChatMessage: (message) => {\n const msg = {\n id: message.id,\n text: message.text,\n sender_id: message.sender_id,\n sender_name: message.sender_name,\n timestamp: Number(message.timestamp),\n reply_to: message.reply_to ?? null,\n target: message.target ?? null,\n };\n this.state.addChatMessage(msg);\n this.events.onChatMessage?.(msg);\n },\n\n onJoinRequested: (request) => {\n const requestId = request?.request_id || request?.requestId;\n const participantId = request?.user_id || request?.participantId;\n const nameValue =\n request?.user_metadata?.name ||\n request?.display_name ||\n request?.name ||\n \"Participant\";\n\n if (!requestId || !participantId) {\n return;\n }\n\n this.events.onEntryRequested?.({\n requestId,\n participantId,\n name: nameValue,\n });\n },\n\n // PARTICIPANTS\n onParticipantJoined: (participant) => {\n const pid = participant.participant_id;\n\n if (!pid || pid === this.myId) {\n return;\n }\n\n const pname =\n participant.user_metadata?.name ||\n participant.display_name ||\n \"Participant\";\n\n this.state.addParticipant({\n id: pid,\n name: pname,\n connectionState: \"connected\",\n media: {\n micEnabled: true,\n camEnabled: true,\n isScreenSharing: false,\n stream: null,\n },\n });\n\n this.events.onUserJoined?.({\n id: pid,\n name: pname,\n });\n },\n\n onParticipantPresence: (participantId, presence) => {\n if (participantId === this.myId) {\n return;\n }\n\n const current = this.state.getParticipant(participantId);\n\n if (!current) {\n return;\n }\n\n const connectionState =\n presence === \"reconnecting\"\n ? \"reconnecting\"\n : presence === \"connected\" || presence === \"online\"\n ? \"connected\"\n : presence === \"disconnected\"\n ? \"disconnected\"\n : current.connectionState;\n\n this.state.updateParticipantMedia(participantId, {\n stream: current.media?.stream ?? null,\n });\n\n const next = new Map(this.state.participants);\n\n next.set(participantId, {\n ...current,\n connectionState,\n });\n\n this.state.participants = next;\n\n this.state.notify(`participant:${participantId}`);\n\n this.state.notify(\"participants\");\n },\n\n onParticipantLeft: (participant) => {\n const pid =\n typeof participant === \"string\"\n ? participant\n : participant.participant_id;\n\n if (!pid) {\n return;\n }\n\n console.log(\"[SFU] Participant permanently left\", pid);\n\n this.cleanupRemoteParticipant(pid);\n this.state.removeParticipant(pid);\n this.events.onUserLeft?.(pid);\n },\n\n // TRACKS\n onParticipantMediaState: (participantId, audioMuted, videoMuted) => {\n if (participantId === this.myId) return;\n const participant = this.state.getParticipant(participantId);\n if (!participant) return;\n this.state.updateParticipantMedia(participantId, {\n micEnabled: !audioMuted,\n camEnabled: !videoMuted,\n });\n this.events.onMuteStateChanged?.(participantId, \"audio\", audioMuted);\n this.events.onMuteStateChanged?.(participantId, \"video\", videoMuted);\n },\n\n onTrackPublished: (track) => {\n console.log(\"[SFU] Track published\", track);\n },\n\n onTrackUnpublished: (track) => {\n console.log(\"[SFU] Track unpublished\", track);\n const pid = track.participant_id;\n\n if (!pid) {\n return;\n }\n\n const current = this.state.getParticipant(pid);\n if (track.source === \"screen\") {\n const screen = this.remoteScreenStreams.get(pid);\n\n screen?.getTracks().forEach((t) => t.stop());\n\n this.remoteScreenStreams.delete(pid);\n\n this.state.updateParticipantMedia(pid, {\n isScreenSharing: false,\n screenStream: null,\n screenTrack: undefined,\n });\n\n this.events.onScreenShareStopped?.(pid);\n\n return;\n }\n\n if (!current) {\n return;\n }\n\n this.state.updateParticipantMedia(pid, {\n stream: current.media?.stream ?? null,\n micEnabled:\n track.kind === \"audio\"\n ? false\n : (current.media?.micEnabled ?? true),\n\n camEnabled:\n track.kind === \"video\"\n ? false\n : (current.media?.camEnabled ?? true),\n });\n },\n\n onTrackStateChanged: (track) => {\n const pid = track.participant_id;\n\n if (!pid || pid === this.myId) {\n return;\n }\n\n const current = this.state.getParticipant(pid);\n\n if (!current) {\n return;\n }\n\n if (track.source === \"audio\") {\n this.state.updateParticipantMedia(pid, {\n stream: current.media?.stream ?? null,\n micEnabled: !track.muted,\n });\n\n this.events.onMuteStateChanged?.(pid, \"audio\", track.muted);\n } else if (track.source === \"camera\") {\n this.state.updateParticipantMedia(pid, {\n stream: current.media?.stream ?? null,\n camEnabled: !track.muted,\n });\n\n this.events.onMuteStateChanged?.(pid, \"video\", track.muted);\n }\n\n this.events.onTrackStateChanged?.(track as any);\n },\n\n // RECORDING\n onRecordingStarted: (recording) => {\n this.events.onRecordingStarted?.(recording);\n },\n\n onRecordingStopped: (recording) => {\n this.events.onRecordingStopped?.(recording);\n },\n\n // REMOTE MEDIA\n onRemoteTrack: (track, stream, metadata) => {\n this.handleRemoteTrack(track, stream, metadata);\n },\n\n // SCREEN SHARE\n onScreenShareStarted: (participantId, _track) => {\n console.log(\"[SFU] Screen share started\", participantId);\n\n if (participantId === this.myId) {\n if (!this.screenStream) {\n this.screenStream = this.sfuClient?.getScreenStream() ?? null;\n }\n\n this.state.setPresenterId(participantId);\n this.state.updateLocalParticipant({\n media: {\n isScreenSharing: true,\n screenStream: this.screenStream,\n screenTrack: this.screenStream?.getVideoTracks()[0],\n },\n });\n return;\n }\n\n this.state.setPresenterId(participantId);\n\n // A restarted share can reuse the same remote RTC track and therefore\n // does not necessarily fire another browser ontrack event. Reattach\n // the existing stream to meeting state when the logical start arrives.\n const existingRemoteScreen =\n this.sfuClient?.getRemoteScreenStream(participantId) ??\n this.remoteScreenStreams.get(participantId) ??\n null;\n\n if (existingRemoteScreen) {\n this.remoteScreenStreams.set(participantId, existingRemoteScreen);\n const screenTrack = existingRemoteScreen.getVideoTracks()[0];\n this.state.updateParticipantMedia(participantId, {\n isScreenSharing: true,\n screenStream: existingRemoteScreen,\n screenTrack,\n });\n this.events.onScreenShareStarted?.(participantId, existingRemoteScreen);\n return;\n }\n\n const current = this.state.getParticipant(participantId);\n if (current) {\n this.state.updateParticipantMedia(participantId, {\n isScreenSharing: true,\n screenStream: current.media?.screenStream ?? null,\n screenTrack: current.media?.screenTrack,\n });\n }\n },\n\n onScreenShareStopped: (participantId) => {\n if (this.state.presenterId === participantId) {\n this.state.setPresenterId(null);\n }\n\n if (participantId === this.myId) {\n this.state.updateLocalParticipant({\n media: {\n isScreenSharing: false,\n screenStream: null,\n screenTrack: undefined,\n },\n });\n return;\n }\n\n // Keep the remote stream object alive so a later screen-share-start\n // can reuse the same MediaStreamTrack without waiting for another\n // RTC ontrack event. Only the logical UI state is changed here.\n this.state.updateParticipantMedia(participantId, {\n isScreenSharing: false,\n });\n\n this.events.onScreenShareStopped?.(participantId);\n },\n\n // ERROR\n onError: (error) => {\n console.error(\"[SFU] Error:\", error);\n\n if (\n error?.code === \"request_failed\" ||\n error?.code === \"authorization\"\n ) {\n this.emitError(\"PERMISSION_DENIED\", error.message, error, false);\n\n return;\n }\n\n this.emitError(\n \"SFU_ERROR\",\n error?.message || String(error),\n error,\n true,\n );\n },\n });\n\n /*Assign the client BEFORE starting the connection.\n * This is important because callbacks may fire during\n * getToken().\n */\n this.sfuClient = client;\n\n client.setLocalStream(this.localStream);\n\n await client.getToken(roomId, {\n displayName: name,\n participantId: this.myId,\n audioMuted: this.state.localParticipant?.media?.micEnabled,\n videoMuted: this.state.localParticipant?.media?.camEnabled,\n });\n }\n\n // SFU STATE\n private handleSFUState(state: SFUConnectionState) {\n this.events.onConnectionStateChanged?.(state);\n\n if (state === \"reconnecting\") {\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n });\n\n return;\n }\n\n /*Do NOT emit CONNECTION_LOST while reconnecting.\n * SFUClient should only eventually transition to\n * \"disconnected\" when reconnect attempts are exhausted.\n */\n if (state === \"disconnected\" && !this.intentionalDisconnect) {\n this.emitError(\n \"CONNECTION_LOST\",\n \"Unable to reconnect to SFU server\",\n null,\n true,\n );\n }\n }\n\n // REMOTE TRACKS\n private handleRemoteTrack(\n track: MediaStreamTrack,\n stream: MediaStream,\n metadata: TrackInfo,\n ) {\n const participantId = metadata?.participant_id;\n\n if (!participantId || participantId === this.myId) {\n return;\n }\n\n const source = metadata.source;\n\n /* SCREEN SHARE\n */\n if (source === \"screen\") {\n let screenStream = this.remoteScreenStreams.get(participantId);\n\n if (!screenStream) {\n screenStream = new MediaStream();\n this.remoteScreenStreams.set(participantId, screenStream);\n }\n\n for (const old of screenStream.getVideoTracks()) {\n if (old.id !== track.id) {\n screenStream.removeTrack(old);\n old.stop();\n }\n }\n\n if (!screenStream.getTracks().some((t) => t.id === track.id)) {\n screenStream.addTrack(track);\n }\n\n this.state.updateParticipantMedia(participantId, {\n screenStream,\n screenTrack: track,\n isScreenSharing: true,\n });\n\n this.events.onScreenShareStarted?.(participantId, screenStream);\n\n return;\n }\n\n let remoteStream = this.remoteStreams.get(participantId);\n\n if (!remoteStream) {\n remoteStream = new MediaStream();\n\n this.remoteStreams.set(participantId, remoteStream);\n }\n\n for (const old of remoteStream.getTracks()) {\n if (old.kind === track.kind && old.id !== track.id) {\n remoteStream.removeTrack(old);\n old.stop();\n }\n }\n\n if (!remoteStream.getTracks().some((t) => t.id === track.id)) {\n remoteStream.addTrack(track);\n }\n\n const current = this.state.getParticipant(participantId);\n\n this.state.updateParticipantMedia(participantId, {\n stream: remoteStream,\n cameraTrack: track.kind === \"video\" ? track : current?.media?.cameraTrack,\n audioTrack: track.kind === \"audio\" ? track : current?.media?.audioTrack,\n });\n\n if (track.kind === \"audio\") {\n this.activeSpeakerDetector.addTrack(participantId, track);\n }\n\n this.events.onTrack?.(remoteStream, participantId);\n\n track.onended = () => {\n if (track.kind === \"video\") {\n this.state.updateParticipantMedia(participantId, {\n camEnabled: false,\n stream: remoteStream,\n });\n\n return;\n }\n\n this.state.updateParticipantMedia(participantId, {\n micEnabled: false,\n stream: remoteStream,\n });\n };\n }\n\n // MEETING\n getMeeting(): {\n id: string | null;\n name: string | null;\n } {\n return this.room;\n }\n\n // ADMISSION CONTROL\n async approveJoinRequest(requestId: string) {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.sfuClient.approveJoinRequest(requestId);\n }\n\n async rejectJoinRequest(requestId: string, reason?: string) {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.sfuClient.rejectJoinRequest(requestId, reason);\n }\n\n // MEDIA CONTROL\n toggleMic() {\n const mediaState = this.state.localParticipant?.media;\n\n if (!mediaState || !this.localStream) {\n return;\n }\n\n const nextEnabled = !mediaState.micEnabled;\n\n this.localStream.getAudioTracks().forEach((track) => {\n track.enabled = nextEnabled;\n });\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n media: {\n micEnabled: nextEnabled,\n },\n });\n\n this.sfuClient?.muteAudio(!nextEnabled);\n this.events.onMicToggled?.(this.myId, nextEnabled);\n }\n\n toggleCam() {\n const mediaState = this.state.localParticipant?.media;\n\n if (!mediaState || !this.localStream) {\n return;\n }\n\n const nextEnabled = !mediaState.camEnabled;\n\n this.localStream.getVideoTracks().forEach((track) => {\n track.enabled = nextEnabled;\n });\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n media: {\n camEnabled: nextEnabled,\n },\n });\n\n this.sfuClient?.muteVideo(!nextEnabled);\n\n this.events.onCamToggled?.(this.myId, nextEnabled);\n }\n\n // SCREEN SHARING\n async startScreenShare() {\n try {\n if (!navigator.mediaDevices?.getDisplayMedia) {\n throw new Error(\"Screen sharing not supported on this device\");\n }\n\n if (!this.sfuClient) {\n throw new Error(\"Cannot share screen before joining the meeting\");\n }\n\n this.screenStream = await this.sfuClient.shareScreen();\n\n this.isScreenSharing = true;\n\n this.state.updateLocalParticipant({\n media: {\n isScreenSharing: true,\n screenStream: this.screenStream,\n screenTrack: this.screenStream?.getVideoTracks()[0],\n },\n });\n\n return this.screenStream;\n } catch (err: any) {\n this.emitError(\n \"SCREEN_SHARE_FAILED\",\n err?.message || \"Failed to start screen sharing\",\n err,\n true,\n );\n\n this.isScreenSharing = false;\n this.screenStream = null;\n\n throw err;\n }\n }\n\n async stopScreenShare() {\n if (!this.sfuClient) {\n return;\n }\n\n try {\n await this.sfuClient.stopScreenShare();\n } finally {\n this.screenStream = null;\n this.isScreenSharing = false;\n\n this.state.updateLocalParticipant({\n media: {\n isScreenSharing: false,\n screenStream: null,\n screenTrack: undefined,\n },\n });\n }\n }\n\n // RECORDING\n async startRecording() {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n await this.sfuClient.startRecording();\n }\n\n async stopRecording() {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n await this.sfuClient.stopRecording();\n }\n\n async getRecordingStatus(): Promise<{\n recording: RecordingInfo | null;\n }> {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.sfuClient.getRecordingStatus();\n }\n\n // CHAT\n\n sendChatMessage(payload: ChatInput) {\n if (!this.sfuClient) {\n console.warn(\"SFU Client not connected\");\n return;\n }\n\n const message = payload.message.trim();\n if (!message) return;\n\n this.sfuClient.sendChatMessage({\n message,\n reply_to: payload.reply_to ?? null,\n target: payload.target ?? null,\n });\n }\n\n sendReaction(reaction: string): void {\n if (!this.sfuClient) {\n console.warn(\"SFU Client not connected\");\n return;\n }\n this.sfuClient.sendReaction(reaction);\n }\n\n // CLEANUP\n private cleanupRemoteParticipant(participantId: string) {\n this.activeSpeakerDetector.removeParticipant(participantId);\n\n const stream = this.remoteStreams.get(participantId);\n\n stream?.getTracks().forEach((track) => track.stop());\n\n this.remoteStreams.delete(participantId);\n\n const screen = this.remoteScreenStreams.get(participantId);\n\n screen?.getTracks().forEach((track) => track.stop());\n\n this.remoteScreenStreams.delete(participantId);\n }\n\n // DISCONNECT\n async disconnect(): Promise<void> {\n if (this.disconnectPromise) {\n return this.disconnectPromise;\n }\n\n this.disconnectPromise = this.performDisconnect();\n\n try {\n await this.disconnectPromise;\n } finally {\n this.disconnectPromise = null;\n }\n }\n\n private async performDisconnect() {\n this.intentionalDisconnect = true;\n this.joinPromise = null;\n\n const client = this.sfuClient;\n this.sfuClient = null;\n\n if (client) {\n await client.leave();\n }\n\n // LOCAL MEDIA\n if (this.localStream) {\n this.localStream.getTracks().forEach((track) => track.stop());\n\n this.localStream = null;\n }\n\n if (this.screenStream) {\n this.screenStream.getTracks().forEach((track) => track.stop());\n this.screenStream = null;\n }\n\n this.isScreenSharing = false;\n\n // REMOTE MEDIA\n for (const stream of this.remoteStreams.values()) {\n stream.getTracks().forEach((track) => track.stop());\n }\n\n this.remoteStreams.clear();\n for (const stream of this.remoteScreenStreams.values()) {\n stream.getTracks().forEach((track) => track.stop());\n }\n\n this.remoteScreenStreams.clear();\n this.room.id = null;\n this.room.name = null;\n\n this.state.localParticipant = null;\n\n this.state.notify(\"localParticipant\");\n\n this.state.resetRemoteState();\n this.events.onMeetingLeft?.();\n }\n}\n","import { useEffect, useState } from \"react\";\nimport { StateScope } from \"../types/meeting\";\nimport { MeetingState } from \"../core/MeetingState\";\n\nexport function useMeetingStore<T>(\n stateManager: MeetingState,\n scope: StateScope,\n selector: (state: MeetingState) => T,\n): T {\n const [state, setState] = useState(() => selector(stateManager));\n\n useEffect(() => {\n // Update local react state whenever the SDK notifies this scope\n const unsubscribe = stateManager.subscribe(scope, () => {\n setState(selector(stateManager));\n });\n\n return unsubscribe;\n }, [stateManager, scope, selector]);\n\n return state;\n}\n","import { useEffect } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\n\nexport const useMeeting = (handlers?: {\n onError?: (err: any) => void;\n onEntryRequested?: (req: any) => void;\n onEntryResponded?: (payload: any, decision?: any) => void;\n onMeetingLeft?: () => void;\n onTrackStateChanged?: (track: any) => void;\n onRecordingStarted?: (recording: any) => void;\n onRecordingStopped?: (recording: any) => void;\n onReaction?: (reaction: any) => void;\n onActiveSpeakersChanged?: (participantIds: string[]) => void;\n}) => {\n const ctx = useMeetingContext();\n\n // Error Handler\n useEffect(() => {\n if (!handlers?.onError) return;\n return ctx.onError(handlers.onError);\n }, [handlers?.onError]);\n\n useEffect(() => {\n if (!handlers?.onActiveSpeakersChanged) return;\n\n return ctx.onActiveSpeakersChanged(handlers.onActiveSpeakersChanged);\n }, [handlers?.onActiveSpeakersChanged]);\n\n // Entry Request Handler\n useEffect(() => {\n if (!handlers?.onEntryRequested) return;\n return ctx.onEntryRequested(handlers.onEntryRequested);\n }, [handlers?.onEntryRequested]);\n\n // Entry Response Handler\n useEffect(() => {\n if (!handlers?.onEntryResponded) return;\n return ctx.onEntryResponded(handlers.onEntryResponded);\n }, [handlers?.onEntryResponded]);\n\n // Meeting Left Handler\n useEffect(() => {\n if (!handlers?.onMeetingLeft) return;\n return ctx.onMeetingLeft(handlers.onMeetingLeft);\n }, [handlers?.onMeetingLeft]);\n\n useEffect(() => {\n if (!handlers?.onTrackStateChanged) return;\n return ctx.onTrackStateChanged(handlers.onTrackStateChanged);\n }, [handlers?.onTrackStateChanged]);\n\n useEffect(() => {\n if (!handlers?.onRecordingStarted) return;\n return ctx.onRecordingStarted(handlers.onRecordingStarted);\n }, [handlers?.onRecordingStarted]);\n\n useEffect(() => {\n if (!handlers?.onRecordingStopped) return;\n return ctx.onRecordingStopped(handlers.onRecordingStopped);\n }, [handlers?.onRecordingStopped]);\n\n useEffect(() => {\n if (!handlers?.onReaction) return;\n return ctx.onReaction(handlers.onReaction);\n }, [handlers?.onReaction]);\n\n const { sdk: _, ...publicApi } = ctx;\n return publicApi;\n};\n","import { useEffect, useState } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\nimport { Participant } from \"../types/meeting\";\n\nexport const useParticipants = () => {\n const { sdk } = useMeetingContext();\n\n const [participants, setParticipants] = useState<Participant[]>(() =>\n sdk.state.getParticipants(),\n );\n\n useEffect(() => {\n const update = () => {\n setParticipants(sdk.state.getParticipants());\n };\n\n update();\n\n const unsub = sdk.state.subscribe(\"participants\", update);\n\n return unsub;\n }, [sdk]);\n\n return participants;\n};\n","import { useEffect, useRef, useState } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\nimport { Participant } from \"../types/meeting\";\n\nexport const useRemoteMedia = (participantId: string) => {\n const { sdk } = useMeetingContext();\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const audioRef = useRef<HTMLAudioElement | null>(null);\n\n const [participant, setParticipant] = useState<Participant | null>(\n () => sdk.state.getParticipant(participantId) || null,\n );\n\n useEffect(() => {\n const unsub = sdk.state.subscribe(`participant:${participantId}`, () => {\n const p = sdk.state.getParticipant(participantId);\n setParticipant(p ? { ...p } : null);\n });\n\n return unsub;\n }, [participantId, sdk]);\n\n useEffect(() => {\n const stream = participant?.media?.stream;\n if (!stream) return;\n\n // VIDEO\n if (videoRef.current) {\n videoRef.current.srcObject = stream;\n videoRef.current.muted = true;\n videoRef.current.playsInline = true;\n videoRef.current.play().catch(() => {});\n }\n\n // AUDIO\n if (audioRef.current) {\n audioRef.current.srcObject = stream;\n audioRef.current.play().catch(() => {});\n }\n }, [participant?.media?.stream]);\n\n return {\n videoRef,\n audioRef,\n isCamActive: !!participant?.media?.camEnabled,\n isMicEnabled: !!participant?.media?.micEnabled,\n connectionState: participant?.connectionState,\n };\n};\n","import { useEffect, useState } from \"react\";\nimport { SDK_CONFIG } from \"../config/ws\";\n\ntype LiveRoomState = {\n active: boolean;\n count: number;\n canJoin: boolean;\n approved: boolean;\n isHost: boolean;\n hasMoreParticipants: boolean;\n participants: {\n id: string;\n name: string;\n isHost: boolean;\n isPresenter: boolean;\n micEnabled: boolean;\n camEnabled: boolean;\n }[];\n room?: {\n id: string;\n name: string;\n room_code: string;\n capacity: number;\n is_private: boolean;\n };\n};\n\n/**\n * Current SFU does not expose the old `/watch/:room` mesh presence socket.\n * Preview therefore uses the authoritative REST room endpoint and polls it.\n * Live participant/media state begins after JOIN over the SFU WebSocket.\n */\nexport function useMeetingPreview(roomId: string, participantId: string) {\n const [room, setRoom] = useState<LiveRoomState | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [isConnected, setIsConnected] = useState(false);\n const [isLoading, setIsLoading] = useState(true);\n\n useEffect(() => {\n if (!roomId) {\n setIsLoading(false);\n return;\n }\n\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n const load = async () => {\n try {\n const response = await fetch(\n `${SDK_CONFIG.apiBase}/rooms/${encodeURIComponent(roomId)}`,\n );\n\n if (!response.ok) {\n throw new Error(`Room lookup failed (${response.status})`);\n }\n\n const data = await response.json();\n if (stopped) return;\n\n setRoom({\n active: true,\n // The current REST room model intentionally does not expose a live\n // participant count. Do not fabricate one.\n count: 0,\n canJoin: !data.is_private,\n approved: false,\n isHost: false,\n hasMoreParticipants: false,\n participants: [],\n room: {\n id: data.id,\n name: data.name,\n room_code: data.room_code,\n capacity: data.capacity,\n is_private: data.is_private,\n },\n });\n setError(null);\n setIsConnected(true);\n setIsLoading(false);\n } catch (err: any) {\n if (stopped) return;\n setError(err?.message || \"Failed to load room\");\n setIsConnected(false);\n setIsLoading(false);\n } finally {\n if (!stopped) {\n timer = setTimeout(load, 5000);\n }\n }\n };\n\n void load();\n\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n };\n }, [roomId, participantId]);\n\n return {\n room,\n isConnected,\n isLoading,\n error,\n };\n}\n"],"mappings":"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","names":["import_react","import_react","message","import_react","import_react","import_react","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/react/useLocalParticipant.tsx","../src/react/MeetingProvider.tsx","../src/config/ws.ts","../src/core/ActiveSpeakerDetector.ts","../src/core/MeetingState.ts","../src/core/SFUClient.ts","../src/core/VideoCore.ts","../src/react/useMeetingStore.ts","../src/react/useMeeting.ts","../src/react/useParticipants.ts","../src/react/useRemoteMedia.ts","../src/react/useMeetingPreview.ts"],"sourcesContent":["export { useLocalParticipant } from \"./react/useLocalParticipant\";\n\n// Core exports\nexport { VideoSDKCore } from \"./core/VideoCore\";\nexport { SFUClient } from \"./core/SFUClient\";\nexport type {\n SFUConnectionState,\n TrackInfo,\n ParticipantInfo,\n} from \"./core/SFUClient\";\nexport { MeetingState } from \"./core/MeetingState\";\nexport type {\n Participant,\n ChatInput,\n RecordingInfo,\n Reaction,\n MeetingConfig,\n} from \"./types/meeting\";\n\n// React hooks and components\nexport { MeetingProvider, useMeetingContext } from \"./react/MeetingProvider\";\nexport { useMeeting } from \"./react/useMeeting\";\nexport { useParticipants } from \"./react/useParticipants\";\nexport { useRemoteMedia } from \"./react/useRemoteMedia\";\nexport { useMeetingPreview } from \"./react/useMeetingPreview\";\nexport { ActiveSpeakerDetector } from \"./core/ActiveSpeakerDetector\";\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\nimport { Participant } from \"../types/meeting\";\n\nexport const useLocalParticipant = () => {\n const { sdk } = useMeetingContext();\n\n // Guard the initial state to ensure it matches Participant | null\n const [localParticipant, setLocalParticipant] = useState<Participant | null>(\n () => {\n const current = sdk.state.localParticipant;\n return current && current.id ? (current as Participant) : null;\n },\n );\n\n useEffect(() => {\n const unsubscribe = sdk.state.subscribe(\"localParticipant\", () => {\n const current = sdk.state.localParticipant;\n\n // Safe Type-Guard: Only update if the object has a finalized id\n if (current && current.id) {\n setLocalParticipant({ ...current } as Participant);\n } else {\n setLocalParticipant(null);\n }\n });\n\n return unsubscribe;\n }, [sdk]);\n\n const lastStreamRef = useRef<MediaStream | null>(null);\n\n const videoRef = useCallback(\n (video: HTMLVideoElement | null) => {\n if (!video) return;\n\n const stream = localParticipant?.media?.stream;\n if (!stream) return;\n\n if (lastStreamRef.current === stream) return;\n lastStreamRef.current = stream;\n\n video.srcObject = stream;\n video.autoplay = true;\n video.playsInline = true;\n\n video.play().catch((err) => {\n console.warn(`Autoplay failed for local view:`, err);\n });\n },\n [localParticipant?.media?.stream],\n );\n\n return {\n participant: localParticipant,\n videoRef,\n };\n};\n","import React, { createContext, useContext, useMemo, useRef } from \"react\";\nimport { VideoSDKCore } from \"../core/VideoCore\";\nimport {\n ChatInput,\n ChatMessage,\n Reaction,\n MeetingConfig,\n Participant,\n PubSubTopic,\n Recording,\n} from \"../types/meeting\";\nimport { useMeetingStore } from \"./useMeetingStore\";\n\ntype PubSubHandle = {\n messages: ChatMessage[];\n publish: (input: ChatInput) => void;\n};\n\ntype MeetingContextValue = {\n sdk: VideoSDKCore;\n join: (config?: Omit<MeetingConfig, \"participantId\">) => Promise<void>;\n leave: () => void;\n createRoom: (input: {\n name: string;\n description?: string;\n capacity?: number;\n is_private?: boolean;\n }) => Promise<any>;\n getRoom: (roomCode: string) => Promise<any>;\n deleteRoom: (roomCode: string) => Promise<any>;\n\n toggleMic: () => void;\n toggleCam: () => void;\n\n startScreenShare: () => Promise<MediaStream | null>;\n stopScreenShare: () => void;\n\n sendMessage: (input: ChatInput) => void;\n sendReaction: (emoji: string) => void;\n\n room: { id: string | null; name: string | null };\n localParticipant: Participant | null;\n participants: Map<string, Participant>;\n messages: ChatMessage[];\n presenterId: string | null;\n activeSpeakerIds: string[];\n usePubSub: (topic: PubSubTopic) => PubSubHandle;\n approveJoinRequest: (requestId: string) => void;\n rejectJoinRequest: (requestId: string) => void;\n startRecording: () => Promise<void>;\n stopRecording: () => Promise<void>;\n getRecordingStatus: () => Promise<any>;\n onError: (cb: (err: any) => void) => () => void;\n onEntryRequested: (cb: (req: any) => void) => () => void;\n onEntryResponded: (cb: (payload: any, decision?: any) => void) => () => void;\n onMeetingLeft: (cb: () => void) => () => void;\n onTrackStateChanged: (cb: (track: any) => void) => () => void;\n onRecordingStarted: (cb: (recording: Recording) => void) => () => void;\n onRecordingStopped: (cb: (recording: any) => void) => () => void;\n onReaction: (cb: (reaction: Reaction) => void) => () => void;\n onActiveSpeakersChanged: (\n cb: (participantIds: string[]) => void,\n ) => () => void;\n};\n\nconst MeetingContext = createContext<MeetingContextValue | null>(null);\n\nexport const MeetingProvider = ({\n config,\n children,\n}: {\n config: MeetingConfig;\n children: React.ReactNode;\n}) => {\n const sdkRef = useRef<VideoSDKCore | null>(null);\n const errorListeners = useRef(new Set<(err: any) => void>());\n const entryRequestListeners = useRef(new Set<(req: any) => void>());\n const entryResponseListeners = useRef(\n new Set<(payload: any, decision?: any) => void>(),\n );\n const meetingLeftListeners = useRef(new Set<() => void>());\n const trackStateListeners = useRef(new Set<(track: any) => void>());\n const recordingStartedListeners = useRef(new Set<(recording: any) => void>());\n const recordingStoppedListeners = useRef(new Set<(recording: any) => void>());\n const reactionListeners = useRef(new Set<(reaction: Reaction) => void>());\n const activeSpeakerListeners = useRef(\n new Set<(participantIds: string[]) => void>(),\n );\n\n if (!sdkRef.current) {\n sdkRef.current = new VideoSDKCore(\n {\n participantId: config.participantId,\n },\n {\n onError: (err) => {\n errorListeners.current.forEach((fn) => fn(err));\n },\n\n onEntryRequested: (req) => {\n entryRequestListeners.current.forEach((fn) => fn(req));\n },\n\n onEntryResponded: (p, d) => {\n entryResponseListeners.current.forEach((fn) => fn(p, d));\n },\n\n onMeetingLeft: () => {\n meetingLeftListeners.current.forEach((fn) => fn());\n },\n\n onTrackStateChanged: (track) => {\n trackStateListeners.current.forEach((fn) => fn(track));\n },\n\n onRecordingStarted: (recording) => {\n recordingStartedListeners.current.forEach((fn) => fn(recording));\n },\n\n onRecordingStopped: (recording) => {\n recordingStoppedListeners.current.forEach((fn) => fn(recording));\n },\n\n onReaction: (reaction) => {\n reactionListeners.current.forEach((fn) => fn(reaction));\n },\n },\n );\n }\n const sdk = sdkRef.current;\n const activeSpeakerIds = useMeetingStore(sdk.state, \"activeSpeakers\", (s) =>\n Array.from(s.activeSpeakerIds),\n );\n const presenterId = useMeetingStore(\n sdk.state,\n \"presenter\",\n (s) => s.presenterId,\n );\n const participants = useMeetingStore(\n sdk.state,\n \"participants\",\n (s) => s.participants,\n );\n const localParticipant = useMeetingStore(\n sdk.state,\n \"localParticipant\",\n (s) => s.localParticipant,\n );\n const messages = useMeetingStore(sdk.state, \"chat\", (s) =>\n s.getChatMessages(),\n );\n\n const value = useMemo<MeetingContextValue>(() => {\n return {\n sdk,\n join: (joinConfig?: Omit<MeetingConfig, \"participantId\">) =>\n sdk.joinMeeting({\n ...config,\n ...joinConfig,\n }),\n leave: () => sdk.disconnect(),\n createRoom: sdk.createRoom.bind(sdk),\n getRoom: sdk.getRoom.bind(sdk),\n deleteRoom: sdk.deleteRoom.bind(sdk),\n toggleMic: sdk.toggleMic.bind(sdk),\n toggleCam: sdk.toggleCam.bind(sdk),\n startScreenShare: sdk.startScreenShare.bind(sdk),\n stopScreenShare: sdk.stopScreenShare.bind(sdk),\n sendMessage: sdk.sendChatMessage.bind(sdk),\n sendReaction: sdk.sendReaction.bind(sdk),\n\n room: sdk.getMeeting(),\n localParticipant,\n participants,\n messages,\n presenterId,\n activeSpeakerIds,\n usePubSub: (topic: PubSubTopic) => {\n if (topic !== \"SECURE_CHAT\") {\n throw new Error(`Unsupported PubSub argument: \"${topic}\"`);\n }\n return {\n messages: sdk.state.getChatMessages(),\n publish: sdk.sendChatMessage.bind(sdk),\n };\n },\n approveJoinRequest: sdk.approveJoinRequest.bind(sdk),\n rejectJoinRequest: sdk.rejectJoinRequest.bind(sdk),\n startRecording: sdk.startRecording.bind(sdk),\n stopRecording: sdk.stopRecording.bind(sdk),\n getRecordingStatus: sdk.getRecordingStatus.bind(sdk),\n\n onError: (cb: (err: any) => void) => {\n errorListeners.current.add(cb);\n\n return () => {\n errorListeners.current.delete(cb);\n };\n },\n\n onEntryRequested: (cb: (err: any) => void) => {\n entryRequestListeners.current.add(cb);\n\n return () => {\n entryRequestListeners.current.delete(cb);\n };\n },\n onEntryResponded: (cb: (err: any) => void) => {\n entryResponseListeners.current.add(cb);\n\n return () => {\n entryResponseListeners.current.delete(cb);\n };\n },\n onMeetingLeft: (cb: () => void) => {\n meetingLeftListeners.current.add(cb);\n return () => {\n meetingLeftListeners.current.delete(cb);\n };\n },\n onTrackStateChanged: (cb: (track: any) => void) => {\n trackStateListeners.current.add(cb);\n return () => trackStateListeners.current.delete(cb);\n },\n onRecordingStarted: (cb: (recording: any) => void) => {\n recordingStartedListeners.current.add(cb);\n return () => recordingStartedListeners.current.delete(cb);\n },\n onRecordingStopped: (cb: (recording: any) => void) => {\n recordingStoppedListeners.current.add(cb);\n return () => recordingStoppedListeners.current.delete(cb);\n },\n onReaction: (cb: (reaction: Reaction) => void) => {\n reactionListeners.current.add(cb);\n return () => reactionListeners.current.delete(cb);\n },\n onActiveSpeakersChanged: (cb) => {\n activeSpeakerListeners.current.add(cb);\n\n return () => {\n activeSpeakerListeners.current.delete(cb);\n };\n },\n };\n }, [config, sdk, localParticipant, participants, messages, presenterId]);\n\n return (\n <MeetingContext.Provider value={value}>{children}</MeetingContext.Provider>\n );\n};\n\nexport const useMeetingContext = () => {\n const ctx = useContext(MeetingContext);\n if (!ctx)\n throw new Error(\"useMeetingContext must be used inside <MeetingProvider>\");\n return ctx;\n};\n","/**\n * SDK Configuration for WebSocket and SFU connections\n * Updated to support the new Selective Forwarding Unit (SFU) architecture\n */\n\nexport interface SDKConfig {\n apiBase: string;\n wsBase: string;\n iceServers?: RTCIceServer[];\n connectionTimeout?: number;\n maxReconnectAttempts?: number;\n}\n\nexport const SDK_CONFIG: SDKConfig = {\n apiBase: \"https://sfu-server.duckdns.org/api\",\n wsBase: \"wss://sfu-server.duckdns.org/ws\",\n // Public STUN/TURN servers (fallback)\n iceServers: [\n { urls: [\"stun:stun.l.google.com:19302\"] },\n { urls: [\"stun:stun1.l.google.com:19302\"] },\n ],\n // Connection and reconnection settings\n connectionTimeout: 10000,\n maxReconnectAttempts: 5,\n};\n","type SpeakerState = {\n participantId: string;\n track: MediaStreamTrack;\n stream: MediaStream;\n source: MediaStreamAudioSourceNode;\n analyser: AnalyserNode;\n data: Float32Array<ArrayBuffer>;\n active: boolean;\n lastActiveAt: number;\n};\n\nexport interface ActiveSpeakerDetectorOptions {\n intervalMs?: number;\n threshold?: number;\n releaseThreshold?: number;\n releaseMs?: number;\n onActiveSpeakersChanged?: (participantIds: string[]) => void;\n}\n\nexport class ActiveSpeakerDetector {\n private audioContext: AudioContext | null = null;\n\n private speakers = new Map<string, SpeakerState>();\n\n private timer: ReturnType<typeof setInterval> | null = null;\n\n private readonly intervalMs: number;\n private readonly threshold: number;\n private readonly releaseThreshold: number;\n private readonly releaseMs: number;\n\n private onActiveSpeakersChanged: (participantIds: string[]) => void;\n\n private lastEmitted = \"\";\n\n constructor(options: ActiveSpeakerDetectorOptions = {}) {\n this.intervalMs = options.intervalMs ?? 100;\n this.threshold = options.threshold ?? 0.025;\n this.releaseThreshold = options.releaseThreshold ?? 0.015;\n this.releaseMs = options.releaseMs ?? 600;\n\n this.onActiveSpeakersChanged =\n options.onActiveSpeakersChanged ?? (() => {});\n }\n\n private ensureAudioContext(): AudioContext {\n if (!this.audioContext) {\n const AudioContextClass =\n window.AudioContext ||\n (\n window as typeof window & {\n webkitAudioContext?: typeof AudioContext;\n }\n ).webkitAudioContext;\n\n if (!AudioContextClass) {\n throw new Error(\"Web Audio API is not supported by this browser\");\n }\n\n this.audioContext = new AudioContextClass();\n }\n\n return this.audioContext;\n }\n\n async resume() {\n if (!this.audioContext) return;\n\n if (this.audioContext.state === \"suspended\") {\n try {\n await this.audioContext.resume();\n } catch {\n // Browser may require a user gesture.\n }\n }\n }\n\n addTrack(participantId: string, track: MediaStreamTrack) {\n if (!participantId) return;\n\n if (track.kind !== \"audio\") return;\n\n this.removeParticipant(participantId);\n const context = this.ensureAudioContext();\n const stream = new MediaStream([track]);\n const source = context.createMediaStreamSource(stream);\n const analyser = context.createAnalyser();\n\n analyser.fftSize = 512;\n analyser.smoothingTimeConstant = 0.65;\n analyser.minDecibels = -90;\n analyser.maxDecibels = -10;\n\n source.connect(analyser);\n\n const data = new Float32Array(analyser.fftSize);\n\n const state: SpeakerState = {\n participantId,\n track,\n stream,\n source,\n analyser,\n data,\n active: false,\n lastActiveAt: 0,\n };\n\n this.speakers.set(participantId, state);\n\n track.addEventListener(\n \"ended\",\n () => {\n this.removeParticipant(participantId);\n },\n { once: true },\n );\n\n this.start();\n\n void this.resume();\n }\n\n removeParticipant(participantId: string) {\n const state = this.speakers.get(participantId);\n\n if (!state) return;\n\n state.active = false;\n\n try {\n state.source.disconnect();\n } catch {\n // Already disconnected.\n }\n\n state.stream.getTracks().forEach((track) => {\n if (track !== state.track) {\n track.stop();\n }\n });\n\n this.speakers.delete(participantId);\n\n this.emitIfChanged();\n }\n\n removeTrack(track: MediaStreamTrack) {\n for (const [participantId, state] of this.speakers) {\n if (state.track === track) {\n this.removeParticipant(participantId);\n }\n }\n }\n\n clear() {\n for (const participantId of this.speakers.keys()) {\n this.removeParticipant(participantId);\n }\n\n this.speakers.clear();\n\n this.stop();\n\n this.emitIfChanged(true);\n }\n\n start() {\n if (this.timer) return;\n\n this.timer = setInterval(() => this.sample(), this.intervalMs);\n }\n\n stop() {\n if (!this.timer) return;\n\n clearInterval(this.timer);\n this.timer = null;\n }\n\n private sample() {\n const now = performance.now();\n\n for (const state of this.speakers.values()) {\n if (\n state.track.readyState !== \"live\" ||\n state.track.muted ||\n !state.track.enabled\n ) {\n if (state.active) {\n state.active = false;\n }\n\n continue;\n }\n\n state.analyser.getFloatTimeDomainData(state.data);\n\n let sumSquares = 0;\n\n for (let i = 0; i < state.data.length; i++) {\n const sample = state.data[i];\n sumSquares += sample * sample;\n }\n\n const rms = Math.sqrt(sumSquares / state.data.length);\n\n if (!state.active) {\n if (rms >= this.threshold) {\n state.active = true;\n state.lastActiveAt = now;\n }\n } else {\n if (rms >= this.releaseThreshold) {\n state.lastActiveAt = now;\n } else if (now - state.lastActiveAt >= this.releaseMs) {\n state.active = false;\n }\n }\n }\n\n this.emitIfChanged();\n }\n\n private getActiveSpeakerIds(): string[] {\n return Array.from(this.speakers.values())\n .filter((speaker) => speaker.active)\n .map((speaker) => speaker.participantId);\n }\n\n private emitIfChanged(force = false) {\n const ids = this.getActiveSpeakerIds().sort();\n\n const key = ids.join(\"|\");\n\n if (!force && key === this.lastEmitted) {\n return;\n }\n\n this.lastEmitted = key;\n\n this.onActiveSpeakersChanged(ids);\n }\n\n async destroy() {\n this.clear();\n\n if (this.audioContext) {\n try {\n await this.audioContext.close();\n } catch {\n // Ignore already closed context.\n }\n\n this.audioContext = null;\n }\n }\n}\n","import {\n ChatMessage,\n Listener,\n Participant,\n ParticipantMedia,\n StateScope,\n} from \"../types/meeting\";\n\ntype LocalParticipantPatch = {\n id?: string;\n name?: string;\n media?: Partial<ParticipantMedia>;\n};\n\nexport class MeetingState {\n participants = new Map<string, Participant>();\n localParticipant: Participant | null = null;\n localStream: MediaStream | null = null;\n chatMessages = new Map<string, ChatMessage>();\n presenterId: string | null = null;\n activeSpeakerIds = new Set<string>();\n\n private listeners = new Map<StateScope, Set<Listener>>();\n\n // ---- reactive system ----\n\n subscribe(scope: StateScope, fn: Listener): () => void {\n if (!this.listeners.has(scope)) {\n this.listeners.set(scope, new Set());\n }\n this.listeners.get(scope)!.add(fn);\n\n return () => {\n this.listeners.get(scope)?.delete(fn);\n };\n }\n\n notify(scope: StateScope) {\n this.listeners.get(scope)?.forEach((fn) => fn());\n }\n\n setPresenterId(id: string | null) {\n if (this.presenterId === id) return;\n this.presenterId = id;\n this.notify(\"presenter\");\n this.notify(\"participants\");\n }\n\n setActiveSpeakers(ids: string[]) {\n const next = new Set(ids);\n\n if (\n next.size === this.activeSpeakerIds.size &&\n [...next].every((id) => this.activeSpeakerIds.has(id))\n ) {\n return;\n }\n\n this.activeSpeakerIds = next;\n\n this.notify(\"activeSpeakers\");\n }\n\n // ---- participants ----\n\n addParticipant(p: Participant) {\n if (this.participants.has(p.id)) return false;\n // Fix: Immutable Map update\n const next = new Map(this.participants);\n next.set(p.id, p);\n this.participants = next;\n\n this.notify(\"participants\");\n return true;\n }\n\n removeParticipant(id: string) {\n // Fix: Immutable Map update\n const next = new Map(this.participants);\n next.delete(id);\n this.participants = next;\n\n this.notify(\"participants\");\n }\n\n updateParticipantMedia(\n id: string,\n patch: Partial<NonNullable<Participant[\"media\"]>>,\n ) {\n const p = this.participants.get(id);\n if (!p) return;\n\n const updated: Participant = {\n ...p,\n media: {\n stream: null,\n screenStream: undefined,\n cameraTrack: undefined,\n screenTrack: undefined,\n audioTrack: undefined,\n micEnabled: true,\n camEnabled: true,\n isScreenSharing: false,\n ...p.media,\n ...patch,\n },\n };\n\n // Keep your clean immutable map update\n const next = new Map(this.participants);\n next.set(id, updated);\n this.participants = next;\n\n this.notify(`participant:${id}`);\n this.notify(\"participants\");\n }\n\n updateLocalParticipant(patch: LocalParticipantPatch) {\n const prev = this.localParticipant;\n\n if (!prev) {\n this.localParticipant = {\n id: patch.id ?? \"\",\n name: patch.name ?? \"\",\n media: {\n stream: patch.media?.stream ?? null, // ◄ FIX: Capture the stream from the patch here\n screenStream: patch.media?.screenStream,\n cameraTrack: patch.media?.cameraTrack,\n screenTrack: patch.media?.screenTrack,\n audioTrack: patch.media?.audioTrack,\n micEnabled: patch.media?.micEnabled ?? true,\n camEnabled: patch.media?.camEnabled ?? true,\n isScreenSharing: patch.media?.isScreenSharing ?? false,\n },\n };\n\n this.notify(\"localParticipant\");\n return;\n }\n\n const prevMedia = prev.media ?? {\n stream: null,\n screenStream: undefined,\n cameraTrack: undefined,\n screenTrack: undefined,\n audioTrack: undefined,\n micEnabled: true,\n camEnabled: true,\n isScreenSharing: false,\n };\n\n const nextMedia: ParticipantMedia = {\n stream: patch.media?.stream ?? prevMedia.stream,\n screenStream: patch.media?.screenStream ?? prevMedia.screenStream,\n cameraTrack: patch.media?.cameraTrack ?? prevMedia.cameraTrack,\n screenTrack: patch.media?.screenTrack ?? prevMedia.screenTrack,\n audioTrack: patch.media?.audioTrack ?? prevMedia.audioTrack,\n micEnabled: patch.media?.micEnabled ?? prevMedia.micEnabled,\n camEnabled: patch.media?.camEnabled ?? prevMedia.camEnabled,\n isScreenSharing:\n patch.media?.isScreenSharing ?? prevMedia.isScreenSharing,\n };\n\n this.localParticipant = {\n ...prev,\n id: patch.id ?? prev.id,\n name: patch.name ?? prev.name,\n media: nextMedia,\n };\n\n this.notify(\"localParticipant\");\n }\n\n // ---- chat ----\n\n addChatMessage(msg: ChatMessage) {\n this.chatMessages.set(msg.id, msg);\n this.notify(\"chat\");\n }\n\n getChatMessages() {\n return Array.from(this.chatMessages.values()).sort(\n (a, b) => a.timestamp - b.timestamp,\n );\n }\n\n clearChat() {\n this.chatMessages.clear();\n this.notify(\"chat\");\n }\n\n // ---- helpers ----\n\n getParticipants() {\n return Array.from(this.participants.values());\n }\n\n getParticipant(id: string) {\n return this.participants.get(id) ?? null;\n }\n\n resetRemoteState() {\n this.participants.clear();\n this.chatMessages.clear();\n this.presenterId = null;\n this.activeSpeakerIds = new Set();\n this.notify(\"participants\");\n this.notify(\"chat\");\n this.notify(\"presenter\");\n this.notify(\"activeSpeakers\");\n }\n}\n","/**\n * DefComm SFU client.\n *\n * Signaling is authoritative for admission/session state.\n * WebRTC peer connections are transport state and are recreated only after a\n * successful join/resume. A transient WebSocket close therefore does NOT\n * destroy the local MediaStream or immediately declare the participant gone.\n */\n\nexport type SFUConnectionState =\n | \"idle\"\n | \"connecting\"\n | \"joining\"\n | \"waiting_approval\"\n | \"connected\"\n | \"reconnecting\"\n | \"leaving\"\n | \"disconnected\";\n\nexport interface TrackInfo {\n track_id: string;\n participant_id: string;\n kind: \"audio\" | \"video\";\n source?: \"camera\" | \"screen\" | \"audio\" | string;\n [key: string]: any;\n}\n\nexport interface ParticipantInfo {\n participant_id: string;\n user_metadata?: { name?: string; [key: string]: any };\n display_name?: string;\n [key: string]: any;\n}\n\nexport interface JoinPendingInfo {\n request_id: string;\n room_code?: string;\n message?: string;\n}\n\ninterface SFUClientOptions {\n apiBase?: string;\n wsBase?: string;\n participantId?: string;\n onStateChange?: (state: SFUConnectionState) => void;\n onParticipantJoined?: (participant: ParticipantInfo) => void;\n onParticipantLeft?: (participant: string | ParticipantInfo) => void;\n onParticipantPresence?: (participantId: string, presence: string) => void;\n onTrackPublished?: (track: TrackInfo) => void;\n onTrackUnpublished?: (track: TrackInfo) => void;\n onRemoteTrack?: (\n track: MediaStreamTrack,\n stream: MediaStream,\n metadata: TrackInfo,\n ) => void;\n onConnected?: (payload: any, resumed: boolean) => void;\n onDisconnected?: () => void;\n onReconnecting?: (attempt: number) => void;\n onJoinPending?: (info: JoinPendingInfo) => void;\n onJoinApproved?: (requestId: string) => void;\n onJoinRejected?: (requestId: string, reason?: string) => void;\n onJoinRequested?: (request: any) => void;\n onScreenShareStarted?: (participantId: string, track?: TrackInfo) => void;\n onScreenShareStopped?: (participantId: string, trackId?: string) => void;\n onTrackStateChanged?: (track: TrackInfo) => void;\n onRecordingStarted?: (recording: {\n recording_id: string;\n started_at: string;\n }) => void;\n onRecordingStopped?: (recording: {\n recording_id: string;\n stopped_at: string;\n }) => void;\n onError?: (error: any) => void;\n onChatMessage?: (message: any) => void;\n onReaction?: (reaction: any) => void;\n onRoomUpdate?: (data: any) => void;\n onParticipantMediaState?: (\n participantId: string,\n audioMuted: boolean,\n videoMuted: boolean,\n ) => void;\n autoSubscribe?: boolean;\n}\n\ntype PeerName = \"publisher\" | \"subscriber\";\ntype JoinWaiter = {\n resolve: (value: any) => void;\n reject: (error: any) => void;\n};\n\nexport class SFUClient {\n private apiBase: string;\n private wsBase: string;\n private participantId: string;\n\n private ws: WebSocket | null = null;\n private publisher: RTCPeerConnection | null = null;\n private subscriber: RTCPeerConnection | null = null;\n\n private localStream: MediaStream | null = null;\n private screenStream: MediaStream | null = null;\n private videoSender: RTCRtpSender | null = null;\n private audioSender: RTCRtpSender | null = null;\n private screenSender: RTCRtpSender | null = null;\n private audioTransceiver: RTCRtpTransceiver | null = null;\n private cameraTransceiver: RTCRtpTransceiver | null = null;\n private screenTransceiver: RTCRtpTransceiver | null = null;\n\n private iceServers: RTCIceServer[] = [];\n private requestId = 0;\n private publisherRevision = 0;\n private screenShareGeneration = 0;\n private currentParticipantId: string | null = null;\n private token: string | null = null;\n private room: string | null = null;\n private resumeToken: string | null = null;\n private pendingJoinRequestId: string | null = null;\n private joinOptions: {\n displayName?: string;\n avatarUrl?: string;\n } = {};\n\n private state: SFUConnectionState = \"idle\";\n private intentionalClose = false;\n private leaveAcknowledged = false;\n private joiningWithResume = false;\n private desiredAudioMuted = false;\n private desiredVideoMuted = false;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectAttempt = 0;\n private maxReconnectAttempts = 8;\n private reconnectBaseMs = 750;\n private joinWaiter: JoinWaiter | null = null;\n\n private transportRecoveryInProgress = false;\n private transportRecoveryTimer: ReturnType<typeof setTimeout> | null = null;\n\n private pendingIce: Record<PeerName, RTCIceCandidateInit[]> = {\n publisher: [],\n subscriber: [],\n };\n\n private subscriberNegotiating = false;\n private offerQueue: any[] = [];\n private subscriptionQueue: string[] = [];\n private subscriptionRunning = false;\n private subscriptionWaiters: Array<{\n trackIds: string[];\n resolve: () => void;\n reject: (error: any) => void;\n }> = [];\n\n private subscribedTracks = new Set<string>();\n private trackMetadata = new Map<string, TrackInfo>();\n private participants = new Map<string, ParticipantInfo>();\n private remoteStreams = new Map<string, MediaStream>();\n private remoteScreenStreams = new Map<string, MediaStream>();\n private trackToParticipant = new Map<string, string>();\n private trackToSource = new Map<string, string>();\n private localTrackIds = new Map<\"audio\" | \"camera\" | \"screen\", string>();\n\n private subscriberStatsTimer: ReturnType<typeof setInterval> | null = null;\n\n private onStateChange: (state: SFUConnectionState) => void;\n private onParticipantJoined: (p: ParticipantInfo) => void;\n private onParticipantLeft: (p: string | ParticipantInfo) => void;\n private onParticipantPresence: (id: string, presence: string) => void;\n private onTrackPublished: (t: TrackInfo) => void;\n private onTrackUnpublished: (t: TrackInfo) => void;\n private onRemoteTrack: (\n t: MediaStreamTrack,\n s: MediaStream,\n m: TrackInfo,\n ) => void;\n private onConnected: (p: any, resumed: boolean) => void;\n private onDisconnected: () => void;\n private onReconnecting: (attempt: number) => void;\n private onJoinPending: (info: JoinPendingInfo) => void;\n private onJoinApproved: (requestId: string) => void;\n private onJoinRejected: (requestId: string, reason?: string) => void;\n private onJoinRequested: (request: any) => void;\n private onScreenShareStarted: (\n participantId: string,\n track?: TrackInfo,\n ) => void;\n private onScreenShareStopped: (\n participantId: string,\n trackId?: string,\n ) => void;\n private onTrackStateChanged: (track: TrackInfo) => void;\n private onRecordingStarted: (recording: {\n recording_id: string;\n started_at: string;\n }) => void;\n private onRecordingStopped: (recording: {\n recording_id: string;\n stopped_at: string;\n }) => void;\n private onError: (e: any) => void;\n private onChatMessage: (message: any) => void;\n private onReaction: (reaction: any) => void;\n private onRoomUpdate: (data: any) => void;\n private onParticipantMediaState: (\n participantId: string,\n audioMuted: boolean,\n videoMuted: boolean,\n ) => void;\n private autoSubscribe: boolean;\n\n constructor(options: SFUClientOptions = {}) {\n this.apiBase = options.apiBase || \"https://api.example.com/api\";\n this.wsBase = options.wsBase || \"wss://api.example.com/ws\";\n this.participantId = options.participantId || this.createId();\n\n this.onStateChange = options.onStateChange || (() => {});\n this.onParticipantJoined = options.onParticipantJoined || (() => {});\n this.onParticipantLeft = options.onParticipantLeft || (() => {});\n this.onParticipantPresence = options.onParticipantPresence || (() => {});\n this.onTrackPublished = options.onTrackPublished || (() => {});\n this.onTrackUnpublished = options.onTrackUnpublished || (() => {});\n this.onRemoteTrack = options.onRemoteTrack || (() => {});\n this.onConnected = options.onConnected || (() => {});\n this.onDisconnected = options.onDisconnected || (() => {});\n this.onReconnecting = options.onReconnecting || (() => {});\n this.onJoinPending = options.onJoinPending || (() => {});\n this.onJoinApproved = options.onJoinApproved || (() => {});\n this.onJoinRejected = options.onJoinRejected || (() => {});\n this.onJoinRequested = options.onJoinRequested || (() => {});\n this.onScreenShareStarted = options.onScreenShareStarted || (() => {});\n this.onScreenShareStopped = options.onScreenShareStopped || (() => {});\n this.onTrackStateChanged = options.onTrackStateChanged || (() => {});\n this.onRecordingStarted = options.onRecordingStarted || (() => {});\n this.onRecordingStopped = options.onRecordingStopped || (() => {});\n this.onError = options.onError || console.error;\n this.onChatMessage = options.onChatMessage || (() => {});\n this.onReaction = options.onReaction || (() => {});\n this.onRoomUpdate = options.onRoomUpdate || (() => {});\n this.onParticipantMediaState =\n options.onParticipantMediaState || (() => {});\n this.autoSubscribe = options.autoSubscribe !== false;\n }\n\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n\n private startHeartbeat() {\n this.stopHeartbeat();\n\n this.heartbeatTimer = setInterval(() => {\n if (this.ws?.readyState !== WebSocket.OPEN) return;\n\n this.send({\n type: \"ping\",\n payload: {\n nonce: crypto.randomUUID(),\n },\n });\n }, 10_000);\n }\n\n private stopHeartbeat() {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private createId(): string {\n return typeof crypto !== \"undefined\" && crypto.randomUUID\n ? crypto.randomUUID()\n : `id_${Math.random().toString(36).slice(2)}_${Date.now()}`;\n }\n\n private resumeStorageKey(roomCode: string) {\n return `defcomm:sfu:resume:${roomCode}`;\n }\n\n private loadResumeToken(roomCode: string): string | null {\n try {\n return localStorage.getItem(this.resumeStorageKey(roomCode));\n } catch {\n return null;\n }\n }\n\n private saveResumeToken(roomCode: string, token: string) {\n try {\n localStorage.setItem(this.resumeStorageKey(roomCode), token);\n } catch {\n // Storage can be unavailable in private/SSR environments.\n }\n }\n\n private clearResumeToken(roomCode: string | null) {\n if (!roomCode) return;\n try {\n localStorage.removeItem(this.resumeStorageKey(roomCode));\n } catch {\n // ignore\n }\n }\n\n private setState(next: SFUConnectionState) {\n if (this.state === next) return;\n this.state = next;\n this.onStateChange(next);\n }\n\n getConnectionState(): SFUConnectionState {\n return this.state;\n }\n\n getParticipantId(): string | null {\n return this.currentParticipantId;\n }\n\n getResumeToken(): string | null {\n return this.resumeToken;\n }\n\n getLocalStream(): MediaStream | null {\n return this.localStream;\n }\n\n getScreenStream(): MediaStream | null {\n return this.screenStream;\n }\n\n getRemoteScreenStream(participantId: string): MediaStream | null {\n return this.remoteScreenStreams.get(participantId) || null;\n }\n\n setLocalStream(stream: MediaStream | null) {\n this.localStream = stream;\n }\n\n private nextRequestId(): string {\n return (++this.requestId).toString();\n }\n\n private async request(url: string, options: RequestInit = {}) {\n const res = await fetch(url, {\n headers: { \"Content-Type\": \"application/json\" },\n ...options,\n });\n\n if (!res.ok) {\n let body: any = {};\n try {\n body = await res.json();\n } catch {\n // ignore non-json error bodies\n }\n throw new Error(body.message || res.statusText);\n }\n\n return res.json();\n }\n\n async createRoom(input: {\n name: string;\n description?: string;\n capacity?: number;\n is_private?: boolean;\n }) {\n return this.request(`${this.apiBase}/rooms`, {\n method: \"POST\",\n body: JSON.stringify({\n name: input.name,\n description: input.description ?? \"\",\n capacity: input.capacity ?? 20,\n is_private: input.is_private ?? false,\n }),\n });\n }\n\n async getRoom(roomCode: string) {\n return this.request(\n `${this.apiBase}/rooms/${encodeURIComponent(roomCode)}`,\n );\n }\n\n async deleteRoom(roomCode: string) {\n return this.request(\n `${this.apiBase}/rooms/${encodeURIComponent(roomCode)}`,\n {\n method: \"DELETE\",\n },\n );\n }\n\n async getToken(\n roomCode: string,\n options: {\n displayName?: string;\n avatarUrl?: string;\n participantId?: string;\n audioMuted?: boolean;\n videoMuted?: boolean;\n } = {},\n ) {\n const nextRoom = roomCode.trim();\n if (this.room && this.room !== nextRoom) {\n this.resumeToken = null;\n }\n\n this.room = nextRoom;\n this.joinOptions = {\n displayName: options.displayName,\n avatarUrl: options.avatarUrl,\n };\n if (options.participantId) this.participantId = options.participantId;\n if (typeof options.audioMuted === \"boolean\")\n this.desiredAudioMuted = options.audioMuted;\n if (typeof options.videoMuted === \"boolean\")\n this.desiredVideoMuted = options.videoMuted;\n if (!this.resumeToken) {\n this.resumeToken = this.loadResumeToken(this.room);\n }\n\n const data = await this.request(`${this.apiBase}/token`, {\n method: \"POST\",\n body: JSON.stringify({\n room_code: this.room,\n user_id: this.participantId,\n display_name: options.displayName,\n avatar_url: options.avatarUrl,\n }),\n });\n\n this.token = data?.token;\n if (!this.token) throw new Error(\"Token endpoint returned no token\");\n\n return this.connect(this.token, this.joinOptions);\n }\n\n private async refreshAccessToken() {\n if (!this.room) throw new Error(\"Cannot refresh token without a room\");\n\n const data = await this.request(`${this.apiBase}/token`, {\n method: \"POST\",\n body: JSON.stringify({\n room_code: this.room,\n user_id: this.participantId,\n display_name: this.joinOptions.displayName,\n avatar_url: this.joinOptions.avatarUrl,\n }),\n });\n\n if (!data?.token) throw new Error(\"Token refresh returned no token\");\n this.token = data.token;\n return this.token;\n }\n\n private connect(token: string, options: any = {}) {\n this.token = token;\n this.intentionalClose = false;\n this.setState(this.reconnectAttempt > 0 ? \"reconnecting\" : \"connecting\");\n\n return new Promise<void>((resolve, reject) => {\n this.joinWaiter = { resolve, reject };\n this.openWebSocket(options);\n });\n }\n\n private openWebSocket(options: any = {}) {\n if (!this.token || !this.room) {\n const error = new Error(\"Cannot connect without token and room\");\n this.failJoin(error);\n return;\n }\n\n if (this.ws) {\n try {\n this.ws.onclose = null;\n this.ws.close();\n } catch {\n // ignore\n }\n }\n\n const ws = new WebSocket(\n `${this.wsBase}?access_token=${encodeURIComponent(this.token)}`,\n );\n this.ws = ws;\n\n ws.onopen = () => {\n this.startHeartbeat();\n this.setState(\"joining\");\n this.joiningWithResume = Boolean(this.resumeToken);\n\n const joinPayload: any = {\n token: this.token,\n room_code: this.room,\n resume_token: this.resumeToken,\n display_name: options.displayName,\n avatar_url: options.avatarUrl,\n audio_muted: this.desiredAudioMuted,\n video_muted: this.desiredVideoMuted,\n };\n\n // After approval the Rust server requires the original pending request id.\n if (this.pendingJoinRequestId) {\n this.send({\n type: \"join\",\n request_id: this.pendingJoinRequestId,\n payload: joinPayload,\n });\n } else {\n this.send({ type: \"join\", payload: joinPayload });\n }\n };\n\n ws.onerror = (event) => {\n this.onError(event);\n };\n\n ws.onclose = () => {\n this.stopHeartbeat();\n if (this.ws !== ws) return;\n this.ws = null;\n\n if (this.intentionalClose || this.state === \"leaving\") {\n this.setState(\"disconnected\");\n this.onDisconnected();\n return;\n }\n\n // Keep MediaStreams and logical participant state alive.\n this.setState(\"reconnecting\");\n this.onDisconnected();\n this.scheduleReconnect();\n };\n\n ws.onmessage = async (event) => {\n if (this.ws !== ws) return;\n try {\n const message = JSON.parse(event.data);\n await this.handleServerMessage(message);\n } catch (error) {\n this.onError(error);\n }\n };\n }\n\n private scheduleReconnect() {\n if (this.reconnectTimer || this.intentionalClose) return;\n if (this.reconnectAttempt >= this.maxReconnectAttempts) {\n this.setState(\"disconnected\");\n this.failJoin(new Error(\"SFU reconnect attempts exhausted\"));\n return;\n }\n\n this.reconnectAttempt += 1;\n const delay = Math.min(\n 15000,\n this.reconnectBaseMs * Math.pow(2, this.reconnectAttempt - 1),\n );\n\n this.onReconnecting(this.reconnectAttempt);\n\n this.reconnectTimer = setTimeout(async () => {\n this.reconnectTimer = null;\n try {\n await this.refreshAccessToken();\n this.openWebSocket(this.joinOptions);\n } catch (error) {\n this.onError(error);\n this.scheduleReconnect();\n }\n }, delay);\n }\n\n private failJoin(error: any) {\n if (this.joinWaiter) {\n const waiter = this.joinWaiter;\n this.joinWaiter = null;\n waiter.reject(error);\n }\n }\n\n private resolveJoin(value: any) {\n if (!this.joinWaiter) return;\n const waiter = this.joinWaiter;\n this.joinWaiter = null;\n waiter.resolve(value);\n }\n\n private async handleServerMessage(message: any) {\n const type = message?.type;\n const payload = message?.payload || {};\n\n switch (type) {\n case \"joined\": {\n await this.handleJoined(payload);\n break;\n }\n\n case \"left\": {\n this.leaveAcknowledged = true;\n break;\n }\n\n case \"join_pending\": {\n const requestId = payload.request_id || message.request_id;\n if (!requestId) throw new Error(\"join_pending has no request_id\");\n\n this.pendingJoinRequestId = requestId;\n this.setState(\"waiting_approval\");\n this.onJoinPending({\n request_id: requestId,\n room_code: payload.room_code || this.room || undefined,\n message: payload.message,\n });\n break;\n }\n\n case \"join_approved\": {\n const requestId = payload.request_id || message.request_id;\n if (!requestId) break;\n this.pendingJoinRequestId = requestId;\n this.onJoinApproved(requestId);\n\n // Approval is a direct signal to the waiting session. Continue the join\n // with the same request id; the Rust Room layer performs the admission.\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.setState(\"joining\");\n this.send({\n type: \"join\",\n request_id: requestId,\n payload: {\n token: this.token,\n room_code: this.room,\n resume_token: this.resumeToken,\n display_name: this.joinOptions.displayName,\n avatar_url: this.joinOptions.avatarUrl,\n },\n });\n }\n break;\n }\n\n case \"join_rejected\": {\n const requestId = payload.request_id || message.request_id;\n const reason = payload.reason;\n this.onJoinRejected(requestId, reason);\n this.pendingJoinRequestId = null;\n this.intentionalClose = true;\n this.failJoin(new Error(reason || \"Join request rejected\"));\n break;\n }\n\n case \"join_requested\":\n case \"join_request\": {\n this.onJoinRequested(payload.request || payload);\n break;\n }\n\n case \"publish_answer\": {\n if (!this.publisher) break;\n await this.publisher.setRemoteDescription({\n type: \"answer\",\n sdp: payload.sdp,\n });\n await this.flushPendingIce(\"publisher\");\n break;\n }\n\n case \"subscribe_offer\": {\n this.offerQueue.push(payload);\n if (!this.subscriberNegotiating) await this.processOfferQueue();\n break;\n }\n\n case \"ice_candidate\":\n case \"publisher_ice_candidate\":\n case \"subscriber_ice_candidate\": {\n const candidatePayload = {\n ...payload,\n peer:\n payload.peer ||\n (type === \"publisher_ice_candidate\" ? \"publisher\" : \"subscriber\"),\n };\n await this.handleIce(candidatePayload);\n break;\n }\n\n case \"participant_joined\": {\n const participant = payload.participant || payload;\n const participantId =\n participant?.participant_id || payload.participant_id;\n if (!participantId || participantId === this.currentParticipantId)\n break;\n\n if (participant) this.participants.set(participantId, participant);\n this.onParticipantJoined(participant);\n break;\n }\n\n case \"participant_left\": {\n const participantId = payload.participant_id;\n if (!participantId) break;\n this.participants.delete(participantId);\n this.removeRemoteParticipant(participantId);\n this.onParticipantLeft(participantId);\n break;\n }\n\n case \"participant_media_state\": {\n const participantId = payload.participant_id;\n if (!participantId) break;\n this.onParticipantMediaState(\n participantId,\n Boolean(payload.audio_muted),\n Boolean(payload.video_muted),\n );\n break;\n }\n\n case \"participant_presence\":\n case \"participant_presence_changed\": {\n const participantId = payload.participant_id;\n const presence = payload.presence;\n if (participantId && presence) {\n this.onParticipantPresence(participantId, String(presence));\n }\n break;\n }\n\n case \"track_published\": {\n const track: TrackInfo = payload.track || payload;\n if (!track?.track_id) break;\n this.rememberTrack(track);\n\n if (track.participant_id === this.currentParticipantId) {\n if (track.source === \"audio\") {\n this.localTrackIds.set(\"audio\", track.track_id);\n const muted = !(\n this.localStream?.getAudioTracks()[0]?.enabled ?? true\n );\n this.send({\n type: \"track_state\",\n payload: { track_id: track.track_id, muted },\n });\n }\n if (track.source === \"camera\") {\n this.localTrackIds.set(\"camera\", track.track_id);\n const muted = !(\n this.localStream?.getVideoTracks()[0]?.enabled ?? true\n );\n this.send({\n type: \"track_state\",\n payload: { track_id: track.track_id, muted },\n });\n }\n if (track.source === \"screen\")\n this.localTrackIds.set(\"screen\", track.track_id);\n break;\n }\n\n this.onTrackPublished(track);\n if (this.autoSubscribe) await this.subscribe(track.track_id);\n break;\n }\n\n case \"track_unpublished\": {\n const trackId = payload.track_id || payload.track?.track_id;\n if (!trackId) break;\n const track =\n this.trackMetadata.get(trackId) ||\n ({\n track_id: trackId,\n participant_id: this.trackToParticipant.get(trackId) || \"\",\n source: this.trackToSource.get(trackId),\n kind: \"video\",\n } as TrackInfo);\n\n this.trackMetadata.delete(trackId);\n this.subscribedTracks.delete(trackId);\n this.trackToParticipant.delete(trackId);\n this.trackToSource.delete(trackId);\n\n for (const [source, localId] of this.localTrackIds) {\n if (localId === trackId) this.localTrackIds.delete(source);\n }\n\n if (track.participant_id === this.currentParticipantId) break;\n this.onTrackUnpublished(track);\n break;\n }\n\n case \"track_state_changed\": {\n const trackId = payload.track_id || payload.track?.track_id;\n if (!trackId) break;\n\n const existing = this.trackMetadata.get(trackId);\n const track: TrackInfo = {\n ...(existing || {}),\n ...(payload.track || {}),\n track_id: trackId,\n participant_id:\n payload.participant_id ||\n existing?.participant_id ||\n payload.track?.participant_id,\n kind:\n payload.kind || payload.track?.kind || existing?.kind || \"video\",\n source: payload.source || payload.track?.source || existing?.source,\n muted: Boolean(payload.muted),\n };\n\n if (!track.participant_id) break;\n this.rememberTrack(track);\n this.onTrackStateChanged(track);\n break;\n }\n\n case \"subscription_updated\": {\n // Authoritative acknowledgement of the current subscriber set.\n break;\n }\n\n case \"recording_started\": {\n this.onRecordingStarted({\n recording_id: payload.recording_id,\n started_at: payload.started_at,\n });\n break;\n }\n\n case \"recording_stopped\": {\n this.onRecordingStopped({\n recording_id: payload.recording_id,\n stopped_at: payload.stopped_at,\n });\n break;\n }\n\n case \"reconnecting\": {\n this.setState(\"reconnecting\");\n break;\n }\n\n case \"screen_share_started\": {\n const participantId = payload.participant_id;\n const track = payload.track as TrackInfo | undefined;\n if (track) this.rememberTrack(track);\n if (participantId) this.onScreenShareStarted(participantId, track);\n break;\n }\n\n case \"screen_share_stopped\": {\n const participantId = payload.participant_id;\n const trackId = payload.track_id;\n\n // Keep the underlying remote screen track alive across a logical\n // stop/start. The SFU and publisher reuse the same RTP track.\n this.onScreenShareStopped(participantId, trackId);\n break;\n }\n\n case \"room_state\": {\n const participants = payload.participants || [];\n this.onRoomStateReconciled(payload);\n this.onRoomUpdate(payload);\n for (const participant of participants) {\n const pid = participant?.participant_id;\n if (!pid) continue;\n if (pid !== this.currentParticipantId) {\n this.participants.set(pid, participant);\n this.onParticipantPresence(\n pid,\n String(participant.presence || \"connected\"),\n );\n this.onParticipantMediaState(\n pid,\n Boolean(participant.audio_muted),\n Boolean(participant.video_muted),\n );\n }\n }\n for (const [pid] of this.participants) {\n if (!participants.some((p: any) => p?.participant_id === pid)) {\n this.participants.delete(pid);\n this.removeRemoteParticipant(pid);\n this.onParticipantLeft(pid);\n }\n }\n for (const track of payload.tracks || []) this.rememberTrack(track);\n if (Array.isArray(payload.chat_history)) {\n for (const message of payload.chat_history)\n this.onChatMessage(message);\n }\n break;\n }\n\n case \"chat_message\": {\n const msg = payload.message || payload;\n if (msg?.id) this.onChatMessage(msg);\n break;\n }\n\n case \"reaction\": {\n const reaction = payload.reaction || payload;\n if (reaction?.id && reaction?.emoji) this.onReaction(reaction);\n break;\n }\n\n case \"error\": {\n const message = payload.message || \"SFU signaling error\";\n if (\n this.state === \"reconnecting\" &&\n message.includes(\"participant session is stale\")\n ) {\n console.debug(\n \"[SFU] Ignoring stale-session error during recovery\",\n message,\n );\n return;\n }\n const error = new Error(message);\n if (this.state === \"joining\" || this.state === \"waiting_approval\") {\n this.onError(error);\n this.failJoin(error);\n return;\n }\n this.onError(error);\n break;\n }\n\n default:\n console.debug(\"[SFU] Ignoring unknown server message\", message);\n }\n }\n\n private onRoomStateReconciled(payload: any) {\n const participants = payload.participants || [];\n const local = participants.find(\n (p: any) => p?.participant_id === this.currentParticipantId,\n );\n if (local) {\n this.desiredAudioMuted = Boolean(local.audio_muted);\n this.desiredVideoMuted = Boolean(local.video_muted);\n }\n }\n\n private rememberTrack(track: TrackInfo) {\n this.trackMetadata.set(track.track_id, track);\n this.trackToParticipant.set(track.track_id, track.participant_id);\n if (track.source) this.trackToSource.set(track.track_id, track.source);\n }\n\n private async handleJoined(payload: any) {\n const resumed = this.joiningWithResume;\n this.joiningWithResume = false;\n\n this.iceServers = payload.ice_servers || this.iceServers || [];\n this.currentParticipantId = payload.participant_id;\n this.resumeToken =\n payload.resume_token || payload.resumeToken || this.resumeToken;\n if (this.room && this.resumeToken) {\n this.saveResumeToken(this.room, this.resumeToken);\n }\n this.pendingJoinRequestId = null;\n this.reconnectAttempt = 0;\n\n this.participants.clear();\n this.trackMetadata.clear();\n this.trackToParticipant.clear();\n this.trackToSource.clear();\n this.localTrackIds.clear();\n\n for (const participant of payload.participants || []) {\n if (participant?.participant_id) {\n this.participants.set(participant.participant_id, participant);\n }\n }\n\n for (const track of payload.tracks || []) {\n if (track?.track_id) this.rememberTrack(track);\n }\n\n await this.initializePeerConnections();\n this.setState(\"connected\");\n this.onConnected(payload, resumed);\n\n for (const participant of this.participants.values()) {\n if (participant.participant_id !== this.currentParticipantId) {\n this.onParticipantJoined(participant);\n this.onParticipantPresence(\n participant.participant_id,\n String(participant.presence || \"connected\"),\n );\n this.onParticipantMediaState(\n participant.participant_id,\n Boolean(participant.audio_muted),\n Boolean(participant.video_muted),\n );\n }\n }\n\n if (Array.isArray(payload.chat_history)) {\n for (const message of payload.chat_history) this.onChatMessage(message);\n }\n this.onRoomUpdate(payload);\n\n // A reconnect/resume needs a fresh publisher negotiation and subscription\n // reconciliation because the WebSocket transport was replaced.\n if (this.localStream) {\n await this.publishExistingTracks();\n }\n\n if (this.autoSubscribe) {\n const trackIds = [...this.trackMetadata.values()]\n .filter((track) => track.participant_id !== this.currentParticipantId)\n .map((track) => track.track_id);\n if (trackIds.length) await this.subscribeMultiple(trackIds);\n }\n\n this.resolveJoin(payload);\n }\n\n private async initializePeerConnections() {\n this.closePeerConnectionsOnly();\n this.publisherRevision = 0;\n\n const config: RTCConfiguration = { iceServers: this.iceServers };\n this.publisher = new RTCPeerConnection(config);\n this.subscriber = new RTCPeerConnection(config);\n\n // Keep audio, camera, and screen on three permanent publisher m-lines.\n // This mirrors the working client: screen sharing must never reuse the\n // camera sender/transceiver.\n this.audioTransceiver = this.publisher.addTransceiver(\"audio\", {\n direction: \"sendonly\",\n });\n this.cameraTransceiver = this.publisher.addTransceiver(\"video\", {\n direction: \"sendonly\",\n });\n this.screenTransceiver = this.publisher.addTransceiver(\"video\", {\n direction: \"inactive\",\n });\n\n this.audioSender = this.audioTransceiver.sender;\n this.videoSender = this.cameraTransceiver.sender;\n this.screenSender = this.screenTransceiver.sender;\n\n this.publisher.onicecandidate = (event) => {\n if (event.candidate) this.sendCandidate(\"publisher\", event.candidate);\n };\n\n this.subscriber.onicecandidate = (event) => {\n if (event.candidate) this.sendCandidate(\"subscriber\", event.candidate);\n };\n\n this.publisher.onconnectionstatechange = () => {\n const publisher = this.publisher;\n if (!publisher) return;\n\n const state = publisher.connectionState;\n\n console.debug(\"[SFU] Publisher connection state\", {\n connectionState: publisher.connectionState,\n iceConnectionState: publisher.iceConnectionState,\n iceGatheringState: publisher.iceGatheringState,\n signalingState: publisher.signalingState,\n });\n\n if (state === \"failed\") {\n this.recoverWebRTC(\"publisher_failed\");\n }\n };\n\n this.subscriber.onconnectionstatechange = () => {\n const subscriber = this.subscriber;\n if (!subscriber) return;\n\n const state = subscriber.connectionState;\n\n console.debug(\"[SFU] Subscriber connection state\", {\n connectionState: subscriber.connectionState,\n iceConnectionState: subscriber.iceConnectionState,\n iceGatheringState: subscriber.iceGatheringState,\n signalingState: subscriber.signalingState,\n });\n\n if (state === \"failed\") {\n this.recoverWebRTC(\"subscriber_failed\");\n }\n };\n this.publisher.oniceconnectionstatechange = () => {\n const publisher = this.publisher;\n if (!publisher) return;\n\n console.debug(\"[SFU] Publisher ICE state\", {\n iceConnectionState: publisher.iceConnectionState,\n connectionState: publisher.connectionState,\n });\n };\n\n this.subscriber.oniceconnectionstatechange = () => {\n const subscriber = this.subscriber;\n if (!subscriber) return;\n\n console.debug(\"[SFU] Subscriber ICE state\", {\n iceConnectionState: subscriber.iceConnectionState,\n connectionState: subscriber.connectionState,\n });\n };\n\n this.subscriber.ontrack = (event) => {\n void this.handleRemoteTrack(event);\n };\n\n if (!this.subscriberStatsTimer) {\n this.subscriberStatsTimer = setInterval(() => {\n void this.logSubscriberVideoStats();\n }, 3000);\n }\n }\n\n private async handleRemoteTrack(event: RTCTrackEvent) {\n const stream = event.streams?.[0] || null;\n const metadata = this.resolveRemoteTrackMetadata(event.track, stream);\n\n if (!metadata?.participant_id) {\n this.onError(\n new Error(\n `Remote ${event.track.kind} track ${event.track.id} has no SFU participant mapping`,\n ),\n );\n return;\n }\n\n const participantId = metadata.participant_id;\n const source = String(\n metadata.source || this.trackToSource.get(metadata.track_id) || \"\",\n )\n .trim()\n .toLowerCase();\n\n // Screen is a completely separate media path. Never put it in the\n // participant's normal camera/audio MediaStream.\n if (source === \"screen\" || source === \"screen_share\") {\n let screenStream = this.remoteScreenStreams.get(participantId);\n\n if (!screenStream) {\n screenStream = new MediaStream();\n this.remoteScreenStreams.set(participantId, screenStream);\n }\n\n for (const existing of screenStream.getVideoTracks()) {\n if (existing.id !== event.track.id) {\n screenStream.removeTrack(existing);\n existing.stop();\n }\n }\n\n if (\n !screenStream.getTracks().some((track) => track.id === event.track.id)\n ) {\n screenStream.addTrack(event.track);\n }\n\n event.track.onended = () => {\n try {\n screenStream?.removeTrack(event.track);\n } catch {}\n\n if (screenStream?.getTracks().length === 0) {\n this.remoteScreenStreams.delete(participantId);\n this.onScreenShareStopped(participantId, metadata.track_id);\n }\n };\n\n this.onScreenShareStarted(participantId, metadata);\n this.onRemoteTrack(event.track, screenStream, {\n ...metadata,\n source: \"screen\",\n });\n return;\n }\n\n // Only audio and camera video belong to the normal participant stream.\n if (event.track.kind === \"video\" && source !== \"camera\") {\n this.onError(\n new Error(\n `Refusing to route unknown remote video source to camera: ${metadata.track_id}`,\n ),\n );\n return;\n }\n\n let remoteStream = this.remoteStreams.get(participantId);\n if (!remoteStream) {\n remoteStream = new MediaStream();\n this.remoteStreams.set(participantId, remoteStream);\n }\n\n for (const existing of remoteStream.getTracks()) {\n if (\n existing.kind === event.track.kind &&\n existing.id !== event.track.id\n ) {\n remoteStream.removeTrack(existing);\n existing.stop();\n }\n }\n\n if (\n !remoteStream.getTracks().some((track) => track.id === event.track.id)\n ) {\n remoteStream.addTrack(event.track);\n }\n\n event.track.onended = () => {\n try {\n remoteStream?.removeTrack(event.track);\n } catch {}\n };\n\n this.onRemoteTrack(event.track, remoteStream, {\n ...metadata,\n source: event.track.kind === \"audio\" ? \"audio\" : \"camera\",\n });\n }\n\n private normalizeRemoteTrackId(browserTrackId: string): string {\n return browserTrackId?.startsWith(\"track-\")\n ? browserTrackId.slice(\"track-\".length)\n : browserTrackId;\n }\n\n private resolveRemoteTrackMetadata(\n track: MediaStreamTrack,\n stream: MediaStream | null,\n ): TrackInfo | null {\n const candidates = [\n this.normalizeRemoteTrackId(track.id),\n track.id,\n stream?.id ? this.normalizeRemoteTrackId(stream.id) : null,\n stream?.id || null,\n ].filter(Boolean) as string[];\n\n for (const id of candidates) {\n const metadata = this.trackMetadata.get(id);\n if (metadata) return metadata;\n }\n\n // Never guess by participant + kind. A participant can publish camera\n // and screen simultaneously; guessing is exactly how a screen track can\n // end up in the camera tile.\n return null;\n }\n\n private sendCandidate(peer: PeerName, candidate: RTCIceCandidate) {\n this.send({\n type: \"ice_candidate\",\n payload: {\n peer,\n candidate: candidate.candidate,\n sdp_mid: candidate.sdpMid,\n sdp_mline_index: candidate.sdpMLineIndex,\n username_fragment: candidate.usernameFragment,\n },\n });\n }\n\n private async handleIce(payload: any) {\n const peer: PeerName =\n payload.peer === \"publisher\" ? \"publisher\" : \"subscriber\";\n const pc = peer === \"publisher\" ? this.publisher : this.subscriber;\n\n const candidate: RTCIceCandidateInit = {\n candidate: payload.candidate,\n sdpMid: payload.sdp_mid ?? payload.sdpMid ?? null,\n sdpMLineIndex: payload.sdp_mline_index ?? payload.sdpMLineIndex ?? null,\n usernameFragment:\n payload.username_fragment ?? payload.usernameFragment ?? null,\n };\n\n if (!pc || !pc.remoteDescription) {\n this.pendingIce[peer].push(candidate);\n return;\n }\n\n try {\n await pc.addIceCandidate(candidate);\n } catch (error) {\n this.onError(\n new Error(`Failed to add ${peer} ICE candidate: ${String(error)}`),\n );\n }\n }\n\n private async flushPendingIce(peer: PeerName) {\n const pc = peer === \"publisher\" ? this.publisher : this.subscriber;\n if (!pc || !pc.remoteDescription) return;\n\n const queue = this.pendingIce[peer];\n while (queue.length) {\n const candidate = queue.shift()!;\n try {\n await pc.addIceCandidate(candidate);\n } catch (error) {\n this.onError(\n new Error(\n `Failed to add queued ${peer} ICE candidate: ${String(error)}`,\n ),\n );\n }\n }\n }\n\n private async processOfferQueue() {\n if (!this.subscriber) return;\n\n while (this.offerQueue.length) {\n if (this.subscriberNegotiating) return;\n this.subscriberNegotiating = true;\n const offer = this.offerQueue.shift();\n\n try {\n await this.subscriber.setRemoteDescription({\n type: \"offer\",\n sdp: offer.sdp,\n });\n await this.flushPendingIce(\"subscriber\");\n\n const answer = await this.subscriber.createAnswer();\n await this.subscriber.setLocalDescription(answer);\n\n this.send({\n type: \"subscribe_answer\",\n payload: {\n revision: offer.revision,\n sdp: answer.sdp,\n },\n });\n\n // One subscribe request produces one subscriber offer. Resolve only\n // the waiter belonging to this offer; resolving the entire queue can\n // make later subscribe calls look complete before they were negotiated.\n const waiter = this.subscriptionWaiters.shift();\n waiter?.resolve();\n } catch (error) {\n const waiter = this.subscriptionWaiters.shift();\n if (waiter) {\n waiter.trackIds.forEach((id) => this.subscribedTracks.delete(id));\n waiter.reject(error);\n }\n this.onError(\n new Error(`Failed to process subscriber offer: ${String(error)}`),\n );\n } finally {\n this.subscriberNegotiating = false;\n }\n }\n }\n\n private async subscribe(trackId: string) {\n if (!trackId || this.subscribedTracks.has(trackId)) return;\n this.subscribedTracks.add(trackId);\n this.subscriptionQueue.push(trackId);\n if (!this.subscriptionRunning) await this.processSubscriptionQueue();\n }\n\n private async subscribeMultiple(trackIds: string[]) {\n const uniqueIds = [...new Set(trackIds.filter(Boolean))].filter(\n (id) => !this.subscribedTracks.has(id),\n );\n if (!uniqueIds.length || !this.isSocketOpen()) return;\n\n uniqueIds.forEach((id) => this.subscribedTracks.add(id));\n return new Promise<void>((resolve, reject) => {\n const sent = this.send({\n type: \"subscribe\",\n payload: { track_ids: uniqueIds },\n });\n\n if (!sent) {\n uniqueIds.forEach((id) => this.subscribedTracks.delete(id));\n reject(new Error(\"Signaling socket is not open\"));\n return;\n }\n\n this.subscriptionWaiters.push({\n trackIds: uniqueIds,\n resolve,\n reject,\n });\n });\n }\n\n private async processSubscriptionQueue() {\n this.subscriptionRunning = true;\n try {\n while (this.subscriptionQueue.length) {\n const trackId = this.subscriptionQueue.shift()!;\n if (!this.isSocketOpen()) {\n this.subscribedTracks.delete(trackId);\n continue;\n }\n\n await new Promise<void>((resolve, reject) => {\n const sent = this.send({\n type: \"subscribe\",\n payload: { track_ids: [trackId] },\n });\n\n if (!sent) {\n this.subscribedTracks.delete(trackId);\n reject(new Error(\"Signaling socket is not open\"));\n return;\n }\n\n this.subscriptionWaiters.push({\n trackIds: [trackId],\n resolve,\n reject,\n });\n });\n }\n } finally {\n this.subscriptionRunning = false;\n }\n }\n\n async publish({ audio = true, video = true } = {}) {\n if (!this.publisher)\n throw new Error(\"Publisher PeerConnection is not initialized\");\n\n if (!this.localStream) {\n this.localStream = await navigator.mediaDevices.getUserMedia({\n audio,\n video,\n });\n }\n\n await this.publishExistingTracks(audio, video);\n return this.localStream;\n }\n\n private async publishExistingTracks(audio = true, video = true) {\n if (!this.publisher || !this.localStream) return;\n\n if (\n !this.audioTransceiver ||\n !this.cameraTransceiver ||\n !this.screenTransceiver\n ) {\n throw new Error(\"Publisher transceivers are not initialized\");\n }\n\n const audioTrack = this.localStream\n .getAudioTracks()\n .find((track) => track.readyState === \"live\");\n const cameraTrack = this.localStream\n .getVideoTracks()\n .find((track) => track.readyState === \"live\");\n const screenTrack = this.screenStream\n ?.getVideoTracks()\n .find((track) => track.readyState === \"live\");\n\n await this.audioSender?.replaceTrack(\n audio && audioTrack ? audioTrack : null,\n );\n this.audioTransceiver.direction =\n audio && audioTrack ? \"sendonly\" : \"inactive\";\n\n await this.videoSender?.replaceTrack(\n video && cameraTrack ? cameraTrack : null,\n );\n this.cameraTransceiver.direction =\n video && cameraTrack ? \"sendonly\" : \"inactive\";\n\n await this.screenSender?.replaceTrack(screenTrack || null);\n this.screenTransceiver.direction = screenTrack ? \"sendonly\" : \"inactive\";\n\n if (!audioTrack && !cameraTrack && !screenTrack) return;\n\n const offer = await this.publisher.createOffer();\n await this.publisher.setLocalDescription(offer);\n\n this.send({\n type: \"publish_offer\",\n payload: {\n revision: ++this.publisherRevision,\n sdp: offer.sdp,\n },\n });\n\n if (screenTrack) {\n this.send({ type: \"start_screen_share\" });\n }\n }\n\n async shareScreen() {\n if (!this.publisher) {\n throw new Error(\"Publisher PeerConnection is not initialized\");\n }\n\n if (!this.screenTransceiver || !this.screenSender) {\n throw new Error(\"Screen transceiver is not initialized\");\n }\n\n const existing = this.screenStream;\n const existingTrack = this.screenSender.track;\n\n // Already sharing.\n if (existing || (existingTrack && existingTrack.readyState === \"live\")) {\n return existing;\n }\n\n try {\n await this.screenSender.replaceTrack(null);\n } catch {}\n\n this.screenTransceiver.direction = \"inactive\";\n\n const screenStream = await navigator.mediaDevices.getDisplayMedia({\n video: true,\n audio: false,\n });\n\n const screenTrack = screenStream.getVideoTracks()[0];\n\n if (!screenTrack) {\n screenStream.getTracks().forEach((track) => track.stop());\n throw new Error(\"Screen share returned no video track\");\n }\n\n const generation = ++this.screenShareGeneration;\n\n this.screenStream = screenStream;\n\n try {\n await this.screenSender.replaceTrack(screenTrack);\n\n this.screenTransceiver.direction = \"sendonly\";\n\n this.send({\n type: \"start_screen_share\",\n });\n\n const offer = await this.publisher.createOffer();\n\n await this.publisher.setLocalDescription(offer);\n\n const localDescription = this.publisher.localDescription;\n\n if (!localDescription?.sdp) {\n throw new Error(\"Publisher did not produce a valid screen-share SDP\");\n }\n\n this.send({\n type: \"publish_offer\",\n payload: {\n revision: ++this.publisherRevision,\n sdp: localDescription.sdp,\n },\n });\n\n screenTrack.onended = () => {\n if (generation !== this.screenShareGeneration) {\n return;\n }\n\n void this.stopScreenShare();\n };\n\n return this.screenStream;\n } catch (error) {\n try {\n await this.screenSender.replaceTrack(null);\n } catch {}\n\n this.screenTransceiver.direction = \"inactive\";\n\n screenTrack.onended = null;\n\n screenStream.getTracks().forEach((track) => {\n try {\n track.stop();\n } catch {}\n });\n\n this.screenStream = null;\n\n try {\n this.send({\n type: \"stop_screen_share\",\n });\n } catch {}\n\n throw error;\n }\n }\n\n async stopScreenShare() {\n const stream = this.screenStream;\n const senderTrack = this.screenSender?.track || null;\n\n if (!stream && !senderTrack) {\n return;\n }\n\n ++this.screenShareGeneration;\n\n if (senderTrack) {\n senderTrack.onended = null;\n }\n\n try {\n await this.screenSender?.replaceTrack(null);\n } catch (error) {\n this.onError(error);\n }\n\n if (this.screenTransceiver) {\n this.screenTransceiver.direction = \"inactive\";\n }\n\n try {\n if (this.publisher) {\n const offer = await this.publisher.createOffer();\n\n await this.publisher.setLocalDescription(offer);\n\n const localDescription = this.publisher.localDescription;\n\n if (localDescription?.sdp) {\n this.send({\n type: \"publish_offer\",\n payload: {\n revision: ++this.publisherRevision,\n sdp: localDescription.sdp,\n },\n });\n }\n }\n } catch (error) {\n this.onError(error);\n }\n\n this.send({\n type: \"stop_screen_share\",\n });\n\n stream?.getTracks().forEach((track) => {\n try {\n track.stop();\n } catch {}\n });\n\n this.screenStream = null;\n\n if (this.currentParticipantId) {\n this.onScreenShareStopped(this.currentParticipantId);\n }\n }\n\n muteAudio(muted: boolean) {\n this.desiredAudioMuted = muted;\n this.localStream?.getAudioTracks().forEach((track) => {\n track.enabled = !muted;\n });\n\n this.send({\n type: \"set_media_state\",\n payload: { audio_muted: muted, video_muted: this.desiredVideoMuted },\n });\n\n const trackId = this.localTrackIds.get(\"audio\");\n if (trackId) {\n this.send({\n type: \"track_state\",\n payload: {\n track_id: trackId,\n muted,\n },\n });\n }\n }\n\n muteVideo(muted: boolean) {\n this.desiredVideoMuted = muted;\n this.localStream?.getVideoTracks().forEach((track) => {\n track.enabled = !muted;\n });\n\n this.send({\n type: \"set_media_state\",\n payload: { audio_muted: this.desiredAudioMuted, video_muted: muted },\n });\n\n const trackId = this.localTrackIds.get(\"camera\");\n if (trackId) {\n this.send({\n type: \"track_state\",\n payload: {\n track_id: trackId,\n muted,\n },\n });\n }\n }\n\n sendChatMessage(input: {\n message: string;\n reply_to?: any;\n target?: string | null;\n }) {\n return this.send({\n type: \"send_chat\",\n payload: {\n message: input.message,\n reply_to: input.reply_to ?? null,\n target: input.target ?? null,\n },\n });\n }\n\n async startRecording() {\n if (!this.send({ type: \"start_recording\" })) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n async stopRecording() {\n if (!this.send({ type: \"stop_recording\" })) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n async getRecordingStatus() {\n if (!this.room || !this.token) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.request(\n `${this.apiBase}/rooms/${encodeURIComponent(this.room)}/recording`,\n {\n headers: {\n Authorization: `Bearer ${this.token}`,\n },\n },\n );\n }\n\n async approveJoinRequest(requestId: string) {\n if (!requestId) throw new Error(\"requestId is required\");\n if (\n !this.send({ type: \"approve_join\", payload: { request_id: requestId } })\n ) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n async rejectJoinRequest(requestId: string, reason?: string) {\n if (!requestId) throw new Error(\"requestId is required\");\n if (\n !this.send({\n type: \"reject_join\",\n payload: { request_id: requestId, reason },\n })\n ) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n private isSocketOpen() {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n private send(message: any) {\n if (!this.isSocketOpen()) return false;\n this.ws!.send(\n JSON.stringify({\n request_id: this.nextRequestId(),\n ...message,\n }),\n );\n return true;\n }\n\n sendReaction(reaction: string): void {\n this.send({\n type: \"send_reaction\",\n payload: {\n emoji: reaction,\n },\n });\n }\n\n private removeRemoteParticipant(participantId: string) {\n const stream = this.remoteStreams.get(participantId);\n if (stream) {\n stream.getTracks().forEach((track) => track.stop());\n this.remoteStreams.delete(participantId);\n }\n\n const screenStream = this.remoteScreenStreams.get(participantId);\n if (screenStream) {\n screenStream.getTracks().forEach((track) => track.stop());\n this.remoteScreenStreams.delete(participantId);\n }\n\n for (const [trackId, metadata] of this.trackMetadata) {\n if (metadata.participant_id === participantId) {\n this.trackMetadata.delete(trackId);\n this.subscribedTracks.delete(trackId);\n this.trackToParticipant.delete(trackId);\n this.trackToSource.delete(trackId);\n }\n }\n }\n\n async leave() {\n this.stopHeartbeat();\n this.intentionalClose = true;\n this.setState(\"leaving\");\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n const roomCode = this.room;\n const ws = this.ws;\n this.leaveAcknowledged = false;\n\n if (ws?.readyState === WebSocket.OPEN) {\n await new Promise<void>((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n resolve();\n };\n\n // The normal onmessage path remains authoritative. We only wait for\n // the server's `left` acknowledgement through a short polling window.\n const timeout = setTimeout(finish, 1200);\n\n const check = () => {\n if (this.leaveAcknowledged || this.ws !== ws) {\n clearTimeout(timeout);\n finish();\n return;\n }\n if (ws.readyState !== WebSocket.OPEN) {\n clearTimeout(timeout);\n finish();\n return;\n }\n setTimeout(check, 25);\n };\n\n ws.addEventListener(\n \"close\",\n () => {\n clearTimeout(timeout);\n finish();\n },\n { once: true },\n );\n\n this.send({ type: \"leave\" });\n check();\n });\n\n try {\n ws.close(1000, \"client_leave\");\n } catch {\n // ignore\n }\n }\n\n this.clearResumeToken(roomCode);\n this.cleanupAll();\n this.setState(\"disconnected\");\n }\n\n private closePeerConnectionsOnly() {\n if (this.publisher) {\n try {\n this.publisher.close();\n } catch {\n /* ignore */\n }\n this.publisher = null;\n }\n if (this.subscriber) {\n try {\n this.subscriber.close();\n } catch {\n /* ignore */\n }\n this.subscriber = null;\n }\n this.videoSender = null;\n this.audioSender = null;\n this.screenSender = null;\n this.audioTransceiver = null;\n this.cameraTransceiver = null;\n this.screenTransceiver = null;\n this.pendingIce = { publisher: [], subscriber: [] };\n this.offerQueue = [];\n this.subscriberNegotiating = false;\n this.subscriptionQueue = [];\n this.subscriptionRunning = false;\n this.subscriptionWaiters\n .splice(0)\n .forEach((w) => w.reject(new Error(\"PeerConnection recreated\")));\n this.subscribedTracks.clear();\n }\n\n private cleanupAll() {\n if (this.subscriberStatsTimer) {\n clearInterval(this.subscriberStatsTimer);\n this.subscriberStatsTimer = null;\n }\n\n this.closePeerConnectionsOnly();\n\n this.localStream?.getTracks().forEach((track) => track.stop());\n this.screenStream?.getTracks().forEach((track) => track.stop());\n this.localStream = null;\n this.screenStream = null;\n\n for (const stream of this.remoteStreams.values()) {\n stream.getTracks().forEach((track) => track.stop());\n }\n this.remoteStreams.clear();\n\n for (const stream of this.remoteScreenStreams.values()) {\n stream.getTracks().forEach((track) => track.stop());\n }\n this.remoteScreenStreams.clear();\n\n this.trackMetadata.clear();\n this.trackToParticipant.clear();\n this.trackToSource.clear();\n this.localTrackIds.clear();\n this.participants.clear();\n this.currentParticipantId = null;\n this.resumeToken = null;\n this.pendingJoinRequestId = null;\n this.token = null;\n this.room = null;\n\n if (this.ws) {\n try {\n this.ws.close();\n } catch {\n /* ignore */\n }\n this.ws = null;\n }\n }\n\n private async logSubscriberVideoStats() {\n if (!this.subscriber || this.subscriber.connectionState === \"closed\")\n return;\n try {\n const stats = await this.subscriber.getStats();\n stats.forEach((report: any) => {\n if (\n report.type === \"inbound-rtp\" &&\n (report.kind === \"video\" || report.mediaType === \"video\")\n ) {\n console.debug(\"[SFU] subscriber video\", {\n packetsReceived: report.packetsReceived,\n packetsLost: report.packetsLost,\n framesDecoded: report.framesDecoded,\n frameWidth: report.frameWidth,\n frameHeight: report.frameHeight,\n });\n }\n });\n } catch {\n // stats are diagnostic only\n }\n }\n\n private recoverWebRTC(reason: string) {\n if (this.intentionalClose) return;\n\n if (this.transportRecoveryInProgress) {\n console.debug(\"[SFU] WebRTC recovery already in progress\", {\n reason,\n });\n return;\n }\n\n this.transportRecoveryInProgress = true;\n\n console.warn(\"[SFU] WebRTC transport failed; starting recovery\", {\n reason,\n publisherState: this.publisher?.connectionState,\n publisherIceState: this.publisher?.iceConnectionState,\n subscriberState: this.subscriber?.connectionState,\n subscriberIceState: this.subscriber?.iceConnectionState,\n });\n\n this.setState(\"reconnecting\");\n\n this.transportRecoveryTimer = setTimeout(() => {\n this.transportRecoveryTimer = null;\n\n if (this.intentionalClose) {\n this.transportRecoveryInProgress = false;\n return;\n }\n\n const ws = this.ws;\n\n if (ws && ws.readyState === WebSocket.OPEN) {\n try {\n ws.close(4000, \"webrtc_recovery\");\n } catch (error) {\n console.warn(\"[SFU] Failed to close WebSocket for recovery\", error);\n\n this.transportRecoveryInProgress = false;\n this.scheduleReconnect();\n }\n\n return;\n }\n\n this.transportRecoveryInProgress = false;\n this.scheduleReconnect();\n }, 250);\n }\n}\n","import { SDK_CONFIG } from \"../config/ws\";\nimport {\n ChatInput,\n ChatMessage,\n Reaction,\n Events,\n MeetingConfig,\n SDKError,\n RecordingInfo,\n VideoSDKCoreOptions,\n} from \"../types/meeting\";\nimport { ActiveSpeakerDetector } from \"./ActiveSpeakerDetector\";\nimport { MeetingState } from \"./MeetingState\";\nimport { SFUClient, SFUConnectionState, TrackInfo } from \"./SFUClient\";\n\nexport class VideoSDKCore {\n private sfuClient: SFUClient | null = null;\n private myId: string;\n private room: {\n id: string | null;\n name: string | null;\n } = {\n id: null,\n name: null,\n };\n private localStream: MediaStream | null = null;\n private screenStream: MediaStream | null = null;\n private isScreenSharing = false;\n private participantName = \"\";\n\n public readonly state: MeetingState;\n\n private intentionalDisconnect = false;\n\n private remoteStreams = new Map<string, MediaStream>();\n private remoteScreenStreams = new Map<string, MediaStream>();\n\n private activeSpeakerDetector: ActiveSpeakerDetector;\n\n private joinPromise: Promise<void> | null = null;\n private disconnectPromise: Promise<void> | null = null;\n\n private emitError(\n code: string,\n message: string,\n raw?: any,\n recoverable = true,\n ) {\n const err: SDKError = {\n code,\n message,\n raw,\n roomId: this.room.id,\n participantId: this.myId,\n recoverable,\n };\n\n this.events.onError?.(err);\n\n console.error(\"[MeetingSDK Error]\", err);\n }\n\n constructor(\n options: VideoSDKCoreOptions,\n private events: Events = {},\n private apiBase: string = SDK_CONFIG.apiBase,\n private wsBase: string = SDK_CONFIG.wsBase,\n ) {\n this.state = new MeetingState();\n this.events = events;\n this.activeSpeakerDetector = new ActiveSpeakerDetector({\n onActiveSpeakersChanged: (participantIds) => {\n this.state.setActiveSpeakers(participantIds);\n\n this.events.onActiveSpeakersChanged?.(participantIds);\n },\n });\n this.myId = options.participantId;\n }\n\n // LOCAL MEDIA\n\n async initLocal(video: HTMLVideoElement, name: string) {\n this.participantName = name;\n\n try {\n this.localStream = await navigator.mediaDevices.getUserMedia({\n video: {\n width: { ideal: 1280 },\n height: { ideal: 720 },\n },\n audio: {\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n },\n });\n\n const localAudioTrack = this.localStream.getAudioTracks()[0];\n\n if (localAudioTrack) {\n this.activeSpeakerDetector.addTrack(this.myId, localAudioTrack);\n }\n\n const hasVideo = this.localStream\n .getVideoTracks()\n .some((t) => t.readyState === \"live\");\n\n const hasAudio = this.localStream\n .getAudioTracks()\n .some((t) => t.readyState === \"live\");\n\n if (!hasVideo || !hasAudio) {\n throw new Error(`Missing tracks: video=${hasVideo}, audio=${hasAudio}`);\n }\n\n video.srcObject = this.localStream;\n\n this.updateLocalMedia();\n } catch (err: any) {\n this.emitError(\"GET_USER_MEDIA_FAILED\", err?.message, err, false);\n\n throw err;\n }\n }\n\n private updateLocalMedia(audioMuted = false, videoMuted = false) {\n if (!this.localStream) return;\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n\n media: {\n stream: this.localStream,\n cameraTrack: this.localStream.getVideoTracks()[0],\n audioTrack: this.localStream.getAudioTracks()[0],\n micEnabled:\n this.localStream.getAudioTracks()[0]?.enabled ?? !audioMuted,\n camEnabled:\n this.localStream.getVideoTracks()[0]?.enabled ?? !videoMuted,\n isScreenSharing: this.isScreenSharing,\n screenStream: this.screenStream,\n screenTrack: this.screenStream?.getVideoTracks()[0],\n },\n });\n\n this.state.localStream = this.localStream;\n }\n\n // ROOM MANAGEMENT\n async createRoom(input: {\n name: string;\n description?: string;\n capacity?: number;\n is_private?: boolean;\n }) {\n const client =\n this.sfuClient ??\n new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n participantId: this.myId,\n });\n\n return client.createRoom(input);\n }\n\n async getRoom(roomCode: string) {\n const client =\n this.sfuClient ??\n new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n participantId: this.myId,\n });\n\n return client.getRoom(roomCode);\n }\n\n async deleteRoom(roomCode: string) {\n const client =\n this.sfuClient ??\n new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n participantId: this.myId,\n });\n\n return client.deleteRoom(roomCode);\n }\n\n // JOIN\n async joinMeeting(\n config: Omit<MeetingConfig, \"participantId\">,\n ): Promise<void> {\n const { roomId, name, audioMuted = false, videoMuted = false } = config;\n\n if (!roomId || !name) {\n throw new Error(\"roomId and name are required to join meeting\");\n }\n\n if (!this.myId) {\n throw new Error(\"participantId is required\");\n }\n\n /*Already connected?\n * Calling join() again must NOT cause leave().\n */\n if (\n this.sfuClient &&\n this.room.id === roomId &&\n this.sfuClient.getConnectionState() === \"connected\"\n ) {\n console.info(\"[SDK] Already connected; duplicate join ignored\", {\n roomId,\n participantId: this.myId,\n });\n\n return;\n }\n\n if (this.joinPromise) {\n console.info(\n \"[SDK] Join already in progress; waiting for existing join\",\n {\n roomId,\n participantId: this.myId,\n },\n );\n\n return this.joinPromise;\n }\n\n if (this.sfuClient && this.room.id && this.room.id !== roomId) {\n throw new Error(\n `Already connected to room ${this.room.id}. Leave the current meeting before joining another room.`,\n );\n }\n\n this.intentionalDisconnect = false;\n this.participantName = name;\n this.room.id = roomId;\n this.room.name = name;\n\n if (!this.localStream) {\n this.localStream = await navigator.mediaDevices.getUserMedia({\n video: true,\n audio: true,\n });\n\n const localAudioTrack = this.localStream.getAudioTracks()[0];\n\n if (localAudioTrack) {\n this.activeSpeakerDetector.addTrack(this.myId, localAudioTrack);\n }\n }\n\n this.localStream.getAudioTracks().forEach((track) => {\n track.enabled = !audioMuted;\n });\n\n this.localStream.getVideoTracks().forEach((track) => {\n track.enabled = !videoMuted;\n });\n\n this.updateLocalMedia(audioMuted, videoMuted);\n\n const promise = this.connect(roomId, name);\n\n this.joinPromise = promise;\n\n try {\n await promise;\n } finally {\n if (this.joinPromise === promise) {\n this.joinPromise = null;\n }\n }\n }\n\n // SFU CONNECTION\n private async connect(roomId: string, name: string): Promise<void> {\n if (this.sfuClient) {\n const state = this.sfuClient.getConnectionState();\n if (\n this.room.id === roomId &&\n (state === \"connecting\" ||\n state === \"connected\" ||\n state === \"reconnecting\")\n ) {\n console.info(\n \"[SDK] Existing SFU connection is active; connect ignored\",\n {\n roomId,\n state,\n },\n );\n\n return;\n }\n\n throw new Error(\n `SFU client already exists in state \"${state}\". Disconnect explicitly before creating another connection.`,\n );\n }\n\n const client = new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n participantId: this.myId,\n autoSubscribe: true,\n // CONNECTION STATE\n\n onStateChange: (state) => {\n this.handleSFUState(state);\n },\n\n onConnected: (payload, resumed) => {\n console.log(`[SFU] ${resumed ? \"Resumed\" : \"Joined\"} room`, payload);\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n });\n },\n\n onDisconnected: () => {\n /*\n * Disconnected does NOT necessarily mean\n * the participant left the room.\n * SFUClient should attempt reconnect.\n */\n console.log(\"[SFU] Signaling WebSocket disconnected; reconnecting\");\n },\n\n onReconnecting: (attempt) => {\n console.warn(`[SFU] Reconnecting, attempt ${attempt}`);\n },\n\n // ADMISSION CONTROL\n onRoomUpdate: (payload) => {\n const participants = payload?.participants || [];\n const local = participants.find(\n (p: any) => p?.participant_id === this.myId,\n );\n if (local) {\n const media = this.state.localParticipant?.media;\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n media: {\n micEnabled: !Boolean(local.audio_muted),\n camEnabled: !Boolean(local.video_muted),\n isScreenSharing: Boolean(local.screen_sharing),\n screenStream: this.screenStream,\n screenTrack: this.screenStream?.getVideoTracks()[0],\n },\n });\n if (this.localStream) {\n this.localStream.getAudioTracks().forEach((track) => {\n track.enabled = !Boolean(local.audio_muted);\n });\n this.localStream.getVideoTracks().forEach((track) => {\n track.enabled = !Boolean(local.video_muted);\n });\n }\n if (local.screen_sharing) this.state.setPresenterId(this.myId);\n else if (this.state.presenterId === this.myId)\n this.state.setPresenterId(null);\n }\n const presenter = participants.find((p: any) => p?.screen_sharing);\n if (presenter) this.state.setPresenterId(presenter.participant_id);\n else if (!local?.screen_sharing) this.state.setPresenterId(null);\n for (const message of payload?.chat_history || []) {\n this.state.addChatMessage(message);\n }\n this.events.onRoomUpdate?.(payload);\n },\n\n onJoinPending: (info) => {\n // This is the LOCAL participant waiting for host approval. It is not\n // an incoming admission request for the host/moderator UI. Never\n // publish it through onEntryRequested, otherwise the waiting client\n // can render and attempt to approve its own request after reconnect.\n console.log(\"[SFU] Join request pending\", info);\n },\n\n onJoinApproved: (requestId) => {\n console.log(\"[SFU] Join approved\", requestId);\n this.events.onJoinApproved?.(requestId);\n this.events.onEntryResponded?.(\n {\n participantId: this.myId,\n decision: \"approved\",\n },\n\n \"approved\",\n );\n },\n\n onJoinRejected: (requestId, reason) => {\n console.warn(\"[SFU] Join rejected\", requestId, reason);\n this.events.onJoinRejected?.(requestId);\n this.events.onEntryResponded?.(\n {\n participantId: this.myId,\n decision: \"rejected\",\n },\n\n \"rejected\",\n );\n\n this.emitError(\n \"JOIN_REJECTED\",\n reason || \"Your request to join was rejected\",\n {\n requestId,\n reason,\n },\n false,\n );\n },\n\n onChatMessage: (message) => {\n const msg = {\n id: message.id,\n text: message.text,\n sender_id: message.sender_id,\n sender_name: message.sender_name,\n timestamp: Number(message.timestamp),\n reply_to: message.reply_to ?? null,\n target: message.target ?? null,\n };\n this.state.addChatMessage(msg);\n this.events.onChatMessage?.(msg);\n },\n\n onJoinRequested: (request) => {\n const requestId = request?.request_id || request?.requestId;\n const participantId = request?.user_id || request?.participantId;\n const nameValue =\n request?.user_metadata?.name ||\n request?.display_name ||\n request?.name ||\n \"Participant\";\n\n if (!requestId || !participantId) {\n return;\n }\n\n this.events.onEntryRequested?.({\n requestId,\n participantId,\n name: nameValue,\n });\n },\n\n // PARTICIPANTS\n onParticipantJoined: (participant) => {\n const pid = participant.participant_id;\n\n if (!pid || pid === this.myId) {\n return;\n }\n\n const pname =\n participant.user_metadata?.name ||\n participant.display_name ||\n \"Participant\";\n\n this.state.addParticipant({\n id: pid,\n name: pname,\n connectionState: \"connected\",\n media: {\n micEnabled: true,\n camEnabled: true,\n isScreenSharing: false,\n stream: null,\n },\n });\n\n this.events.onUserJoined?.({\n id: pid,\n name: pname,\n });\n },\n\n onParticipantPresence: (participantId, presence) => {\n if (participantId === this.myId) {\n return;\n }\n\n const current = this.state.getParticipant(participantId);\n\n if (!current) {\n return;\n }\n\n const connectionState =\n presence === \"reconnecting\"\n ? \"reconnecting\"\n : presence === \"connected\" || presence === \"online\"\n ? \"connected\"\n : presence === \"disconnected\"\n ? \"disconnected\"\n : current.connectionState;\n\n this.state.updateParticipantMedia(participantId, {\n stream: current.media?.stream ?? null,\n });\n\n const next = new Map(this.state.participants);\n\n next.set(participantId, {\n ...current,\n connectionState,\n });\n\n this.state.participants = next;\n\n this.state.notify(`participant:${participantId}`);\n\n this.state.notify(\"participants\");\n },\n\n onParticipantLeft: (participant) => {\n const pid =\n typeof participant === \"string\"\n ? participant\n : participant.participant_id;\n\n if (!pid) {\n return;\n }\n\n console.log(\"[SFU] Participant permanently left\", pid);\n\n this.cleanupRemoteParticipant(pid);\n this.state.removeParticipant(pid);\n this.events.onUserLeft?.(pid);\n },\n\n // TRACKS\n onParticipantMediaState: (participantId, audioMuted, videoMuted) => {\n if (participantId === this.myId) return;\n const participant = this.state.getParticipant(participantId);\n if (!participant) return;\n this.state.updateParticipantMedia(participantId, {\n micEnabled: !audioMuted,\n camEnabled: !videoMuted,\n });\n this.events.onMuteStateChanged?.(participantId, \"audio\", audioMuted);\n this.events.onMuteStateChanged?.(participantId, \"video\", videoMuted);\n },\n\n onTrackPublished: (track) => {\n console.log(\"[SFU] Track published\", track);\n },\n\n onTrackUnpublished: (track) => {\n console.log(\"[SFU] Track unpublished\", track);\n const pid = track.participant_id;\n\n if (!pid) {\n return;\n }\n\n const current = this.state.getParticipant(pid);\n if (track.source === \"screen\") {\n const screen = this.remoteScreenStreams.get(pid);\n\n screen?.getTracks().forEach((t) => t.stop());\n\n this.remoteScreenStreams.delete(pid);\n\n this.state.updateParticipantMedia(pid, {\n isScreenSharing: false,\n screenStream: null,\n screenTrack: undefined,\n });\n\n this.events.onScreenShareStopped?.(pid);\n\n return;\n }\n\n if (!current) {\n return;\n }\n\n this.state.updateParticipantMedia(pid, {\n stream: current.media?.stream ?? null,\n micEnabled:\n track.kind === \"audio\"\n ? false\n : (current.media?.micEnabled ?? true),\n\n camEnabled:\n track.kind === \"video\"\n ? false\n : (current.media?.camEnabled ?? true),\n });\n },\n\n onTrackStateChanged: (track) => {\n const pid = track.participant_id;\n\n if (!pid || pid === this.myId) {\n return;\n }\n\n const current = this.state.getParticipant(pid);\n\n if (!current) {\n return;\n }\n\n if (track.source === \"audio\") {\n this.state.updateParticipantMedia(pid, {\n stream: current.media?.stream ?? null,\n micEnabled: !track.muted,\n });\n\n this.events.onMuteStateChanged?.(pid, \"audio\", track.muted);\n } else if (track.source === \"camera\") {\n this.state.updateParticipantMedia(pid, {\n stream: current.media?.stream ?? null,\n camEnabled: !track.muted,\n });\n\n this.events.onMuteStateChanged?.(pid, \"video\", track.muted);\n }\n\n this.events.onTrackStateChanged?.(track as any);\n },\n\n // RECORDING\n onRecordingStarted: (recording) => {\n this.events.onRecordingStarted?.(recording);\n },\n\n onRecordingStopped: (recording) => {\n this.events.onRecordingStopped?.(recording);\n },\n\n // REMOTE MEDIA\n onRemoteTrack: (track, stream, metadata) => {\n this.handleRemoteTrack(track, stream, metadata);\n },\n\n // SCREEN SHARE\n onScreenShareStarted: (participantId, _track) => {\n console.log(\"[SFU] Screen share started\", participantId);\n\n if (participantId === this.myId) {\n if (!this.screenStream) {\n this.screenStream = this.sfuClient?.getScreenStream() ?? null;\n }\n\n this.state.setPresenterId(participantId);\n this.state.updateLocalParticipant({\n media: {\n isScreenSharing: true,\n screenStream: this.screenStream,\n screenTrack: this.screenStream?.getVideoTracks()[0],\n },\n });\n return;\n }\n\n this.state.setPresenterId(participantId);\n\n // A restarted share can reuse the same remote RTC track and therefore\n // does not necessarily fire another browser ontrack event. Reattach\n // the existing stream to meeting state when the logical start arrives.\n const existingRemoteScreen =\n this.sfuClient?.getRemoteScreenStream(participantId) ??\n this.remoteScreenStreams.get(participantId) ??\n null;\n\n if (existingRemoteScreen) {\n this.remoteScreenStreams.set(participantId, existingRemoteScreen);\n const screenTrack = existingRemoteScreen.getVideoTracks()[0];\n this.state.updateParticipantMedia(participantId, {\n isScreenSharing: true,\n screenStream: existingRemoteScreen,\n screenTrack,\n });\n this.events.onScreenShareStarted?.(\n participantId,\n existingRemoteScreen,\n );\n return;\n }\n\n const current = this.state.getParticipant(participantId);\n if (current) {\n this.state.updateParticipantMedia(participantId, {\n isScreenSharing: true,\n screenStream: current.media?.screenStream ?? null,\n screenTrack: current.media?.screenTrack,\n });\n }\n },\n\n onScreenShareStopped: (participantId) => {\n if (this.state.presenterId === participantId) {\n this.state.setPresenterId(null);\n }\n\n if (participantId === this.myId) {\n this.state.updateLocalParticipant({\n media: {\n isScreenSharing: false,\n screenStream: null,\n screenTrack: undefined,\n },\n });\n return;\n }\n\n // Keep the remote stream object alive so a later screen-share-start\n // can reuse the same MediaStreamTrack without waiting for another\n // RTC ontrack event. Only the logical UI state is changed here.\n this.state.updateParticipantMedia(participantId, {\n isScreenSharing: false,\n });\n\n this.events.onScreenShareStopped?.(participantId);\n },\n\n // ERROR\n onError: (error) => {\n console.error(\"[SFU] Error:\", error);\n\n if (\n error?.code === \"request_failed\" ||\n error?.code === \"authorization\"\n ) {\n this.emitError(\"PERMISSION_DENIED\", error.message, error, false);\n\n return;\n }\n\n this.emitError(\n \"SFU_ERROR\",\n error?.message || String(error),\n error,\n true,\n );\n },\n });\n\n /*Assign the client BEFORE starting the connection.\n * This is important because callbacks may fire during\n * getToken().\n */\n this.sfuClient = client;\n\n client.setLocalStream(this.localStream);\n\n await client.getToken(roomId, {\n displayName: name,\n participantId: this.myId,\n audioMuted: !(this.localStream?.getAudioTracks()[0]?.enabled ?? true),\n videoMuted: !(this.localStream?.getVideoTracks()[0]?.enabled ?? true),\n });\n }\n\n // SFU STATE\n private handleSFUState(state: SFUConnectionState) {\n this.events.onConnectionStateChanged?.(state);\n\n if (state === \"reconnecting\") {\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n });\n\n return;\n }\n\n /*Do NOT emit CONNECTION_LOST while reconnecting.\n * SFUClient should only eventually transition to\n * \"disconnected\" when reconnect attempts are exhausted.\n */\n if (state === \"disconnected\" && !this.intentionalDisconnect) {\n this.emitError(\n \"CONNECTION_LOST\",\n \"Unable to reconnect to SFU server\",\n null,\n true,\n );\n }\n }\n\n // REMOTE TRACKS\n private handleRemoteTrack(\n track: MediaStreamTrack,\n stream: MediaStream,\n metadata: TrackInfo,\n ) {\n const participantId = metadata?.participant_id;\n\n if (!participantId || participantId === this.myId) {\n return;\n }\n\n const source = metadata.source;\n\n /* SCREEN SHARE\n */\n if (source === \"screen\") {\n let screenStream = this.remoteScreenStreams.get(participantId);\n\n if (!screenStream) {\n screenStream = new MediaStream();\n this.remoteScreenStreams.set(participantId, screenStream);\n }\n\n for (const old of screenStream.getVideoTracks()) {\n if (old.id !== track.id) {\n screenStream.removeTrack(old);\n old.stop();\n }\n }\n\n if (!screenStream.getTracks().some((t) => t.id === track.id)) {\n screenStream.addTrack(track);\n }\n\n this.state.updateParticipantMedia(participantId, {\n screenStream,\n screenTrack: track,\n isScreenSharing: true,\n });\n\n this.events.onScreenShareStarted?.(participantId, screenStream);\n\n return;\n }\n\n let remoteStream = this.remoteStreams.get(participantId);\n\n if (!remoteStream) {\n remoteStream = new MediaStream();\n\n this.remoteStreams.set(participantId, remoteStream);\n }\n\n for (const old of remoteStream.getTracks()) {\n if (old.kind === track.kind && old.id !== track.id) {\n remoteStream.removeTrack(old);\n old.stop();\n }\n }\n\n if (!remoteStream.getTracks().some((t) => t.id === track.id)) {\n remoteStream.addTrack(track);\n }\n\n const current = this.state.getParticipant(participantId);\n\n this.state.updateParticipantMedia(participantId, {\n stream: remoteStream,\n cameraTrack: track.kind === \"video\" ? track : current?.media?.cameraTrack,\n audioTrack: track.kind === \"audio\" ? track : current?.media?.audioTrack,\n });\n\n if (track.kind === \"audio\") {\n this.activeSpeakerDetector.addTrack(participantId, track);\n }\n\n this.events.onTrack?.(remoteStream, participantId);\n\n track.onended = () => {\n if (track.kind === \"video\") {\n this.state.updateParticipantMedia(participantId, {\n camEnabled: false,\n stream: remoteStream,\n });\n\n return;\n }\n\n this.state.updateParticipantMedia(participantId, {\n micEnabled: false,\n stream: remoteStream,\n });\n };\n }\n\n // MEETING\n getMeeting(): {\n id: string | null;\n name: string | null;\n } {\n return this.room;\n }\n\n // ADMISSION CONTROL\n async approveJoinRequest(requestId: string) {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.sfuClient.approveJoinRequest(requestId);\n }\n\n async rejectJoinRequest(requestId: string, reason?: string) {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.sfuClient.rejectJoinRequest(requestId, reason);\n }\n\n // MEDIA CONTROL\n toggleMic() {\n const mediaState = this.state.localParticipant?.media;\n\n if (!mediaState || !this.localStream) {\n return;\n }\n\n const nextEnabled = !mediaState.micEnabled;\n\n this.localStream.getAudioTracks().forEach((track) => {\n track.enabled = nextEnabled;\n });\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n media: {\n micEnabled: nextEnabled,\n },\n });\n\n this.sfuClient?.muteAudio(!nextEnabled);\n this.events.onMicToggled?.(this.myId, nextEnabled);\n }\n\n toggleCam() {\n const mediaState = this.state.localParticipant?.media;\n\n if (!mediaState || !this.localStream) {\n return;\n }\n\n const nextEnabled = !mediaState.camEnabled;\n\n this.localStream.getVideoTracks().forEach((track) => {\n track.enabled = nextEnabled;\n });\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n media: {\n camEnabled: nextEnabled,\n },\n });\n\n this.sfuClient?.muteVideo(!nextEnabled);\n\n this.events.onCamToggled?.(this.myId, nextEnabled);\n }\n\n // SCREEN SHARING\n async startScreenShare() {\n try {\n if (!navigator.mediaDevices?.getDisplayMedia) {\n throw new Error(\"Screen sharing not supported on this device\");\n }\n\n if (!this.sfuClient) {\n throw new Error(\"Cannot share screen before joining the meeting\");\n }\n\n this.screenStream = await this.sfuClient.shareScreen();\n\n this.isScreenSharing = true;\n\n this.state.updateLocalParticipant({\n media: {\n isScreenSharing: true,\n screenStream: this.screenStream,\n screenTrack: this.screenStream?.getVideoTracks()[0],\n },\n });\n\n return this.screenStream;\n } catch (err: any) {\n this.emitError(\n \"SCREEN_SHARE_FAILED\",\n err?.message || \"Failed to start screen sharing\",\n err,\n true,\n );\n\n this.isScreenSharing = false;\n this.screenStream = null;\n\n throw err;\n }\n }\n\n async stopScreenShare() {\n if (!this.sfuClient) {\n return;\n }\n\n try {\n await this.sfuClient.stopScreenShare();\n } finally {\n this.screenStream = null;\n this.isScreenSharing = false;\n\n this.state.updateLocalParticipant({\n media: {\n isScreenSharing: false,\n screenStream: null,\n screenTrack: undefined,\n },\n });\n }\n }\n\n // RECORDING\n async startRecording() {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n await this.sfuClient.startRecording();\n }\n\n async stopRecording() {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n await this.sfuClient.stopRecording();\n }\n\n async getRecordingStatus(): Promise<{\n recording: RecordingInfo | null;\n }> {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.sfuClient.getRecordingStatus();\n }\n\n // CHAT\n\n sendChatMessage(payload: ChatInput) {\n if (!this.sfuClient) {\n console.warn(\"SFU Client not connected\");\n return;\n }\n\n const message = payload.message.trim();\n if (!message) return;\n\n this.sfuClient.sendChatMessage({\n message,\n reply_to: payload.reply_to ?? null,\n target: payload.target ?? null,\n });\n }\n\n sendReaction(reaction: string): void {\n if (!this.sfuClient) {\n console.warn(\"SFU Client not connected\");\n return;\n }\n this.sfuClient.sendReaction(reaction);\n }\n\n // CLEANUP\n private cleanupRemoteParticipant(participantId: string) {\n this.activeSpeakerDetector.removeParticipant(participantId);\n\n const stream = this.remoteStreams.get(participantId);\n\n stream?.getTracks().forEach((track) => track.stop());\n\n this.remoteStreams.delete(participantId);\n\n const screen = this.remoteScreenStreams.get(participantId);\n\n screen?.getTracks().forEach((track) => track.stop());\n\n this.remoteScreenStreams.delete(participantId);\n }\n\n // DISCONNECT\n async disconnect(): Promise<void> {\n if (this.disconnectPromise) {\n return this.disconnectPromise;\n }\n\n this.disconnectPromise = this.performDisconnect();\n\n try {\n await this.disconnectPromise;\n } finally {\n this.disconnectPromise = null;\n }\n }\n\n private async performDisconnect() {\n this.intentionalDisconnect = true;\n this.joinPromise = null;\n\n const client = this.sfuClient;\n this.sfuClient = null;\n\n if (client) {\n await client.leave();\n }\n\n // LOCAL MEDIA\n if (this.localStream) {\n this.localStream.getTracks().forEach((track) => track.stop());\n\n this.localStream = null;\n }\n\n if (this.screenStream) {\n this.screenStream.getTracks().forEach((track) => track.stop());\n this.screenStream = null;\n }\n\n this.isScreenSharing = false;\n\n // REMOTE MEDIA\n for (const stream of this.remoteStreams.values()) {\n stream.getTracks().forEach((track) => track.stop());\n }\n\n this.remoteStreams.clear();\n for (const stream of this.remoteScreenStreams.values()) {\n stream.getTracks().forEach((track) => track.stop());\n }\n\n this.remoteScreenStreams.clear();\n this.room.id = null;\n this.room.name = null;\n\n this.state.localParticipant = null;\n\n this.state.notify(\"localParticipant\");\n\n this.state.resetRemoteState();\n this.events.onMeetingLeft?.();\n }\n}\n","import { useEffect, useState } from \"react\";\nimport { StateScope } from \"../types/meeting\";\nimport { MeetingState } from \"../core/MeetingState\";\n\nexport function useMeetingStore<T>(\n stateManager: MeetingState,\n scope: StateScope,\n selector: (state: MeetingState) => T,\n): T {\n const [state, setState] = useState(() => selector(stateManager));\n\n useEffect(() => {\n // Update local react state whenever the SDK notifies this scope\n const unsubscribe = stateManager.subscribe(scope, () => {\n setState(selector(stateManager));\n });\n\n return unsubscribe;\n }, [stateManager, scope, selector]);\n\n return state;\n}\n","import { useEffect } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\n\nexport const useMeeting = (handlers?: {\n onError?: (err: any) => void;\n onEntryRequested?: (req: any) => void;\n onEntryResponded?: (payload: any, decision?: any) => void;\n onMeetingLeft?: () => void;\n onTrackStateChanged?: (track: any) => void;\n onRecordingStarted?: (recording: any) => void;\n onRecordingStopped?: (recording: any) => void;\n onReaction?: (reaction: any) => void;\n onActiveSpeakersChanged?: (participantIds: string[]) => void;\n}) => {\n const ctx = useMeetingContext();\n\n // Error Handler\n useEffect(() => {\n if (!handlers?.onError) return;\n return ctx.onError(handlers.onError);\n }, [handlers?.onError]);\n\n useEffect(() => {\n if (!handlers?.onActiveSpeakersChanged) return;\n\n return ctx.onActiveSpeakersChanged(handlers.onActiveSpeakersChanged);\n }, [handlers?.onActiveSpeakersChanged]);\n\n // Entry Request Handler\n useEffect(() => {\n if (!handlers?.onEntryRequested) return;\n return ctx.onEntryRequested(handlers.onEntryRequested);\n }, [handlers?.onEntryRequested]);\n\n // Entry Response Handler\n useEffect(() => {\n if (!handlers?.onEntryResponded) return;\n return ctx.onEntryResponded(handlers.onEntryResponded);\n }, [handlers?.onEntryResponded]);\n\n // Meeting Left Handler\n useEffect(() => {\n if (!handlers?.onMeetingLeft) return;\n return ctx.onMeetingLeft(handlers.onMeetingLeft);\n }, [handlers?.onMeetingLeft]);\n\n useEffect(() => {\n if (!handlers?.onTrackStateChanged) return;\n return ctx.onTrackStateChanged(handlers.onTrackStateChanged);\n }, [handlers?.onTrackStateChanged]);\n\n useEffect(() => {\n if (!handlers?.onRecordingStarted) return;\n return ctx.onRecordingStarted(handlers.onRecordingStarted);\n }, [handlers?.onRecordingStarted]);\n\n useEffect(() => {\n if (!handlers?.onRecordingStopped) return;\n return ctx.onRecordingStopped(handlers.onRecordingStopped);\n }, [handlers?.onRecordingStopped]);\n\n useEffect(() => {\n if (!handlers?.onReaction) return;\n return ctx.onReaction(handlers.onReaction);\n }, [handlers?.onReaction]);\n\n const { sdk: _, ...publicApi } = ctx;\n return publicApi;\n};\n","import { useEffect, useState } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\nimport { Participant } from \"../types/meeting\";\n\nexport const useParticipants = () => {\n const { sdk } = useMeetingContext();\n\n const [participants, setParticipants] = useState<Participant[]>(() =>\n sdk.state.getParticipants(),\n );\n\n useEffect(() => {\n const update = () => {\n setParticipants(sdk.state.getParticipants());\n };\n\n update();\n\n const unsub = sdk.state.subscribe(\"participants\", update);\n\n return unsub;\n }, [sdk]);\n\n return participants;\n};\n","import { useEffect, useRef, useState } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\nimport { Participant } from \"../types/meeting\";\n\nexport const useRemoteMedia = (participantId: string) => {\n const { sdk } = useMeetingContext();\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const audioRef = useRef<HTMLAudioElement | null>(null);\n\n const [participant, setParticipant] = useState<Participant | null>(\n () => sdk.state.getParticipant(participantId) || null,\n );\n\n useEffect(() => {\n const unsub = sdk.state.subscribe(`participant:${participantId}`, () => {\n const p = sdk.state.getParticipant(participantId);\n setParticipant(p ? { ...p } : null);\n });\n\n return unsub;\n }, [participantId, sdk]);\n\n useEffect(() => {\n const stream = participant?.media?.stream;\n if (!stream) return;\n\n // VIDEO\n if (videoRef.current) {\n videoRef.current.srcObject = stream;\n videoRef.current.muted = true;\n videoRef.current.playsInline = true;\n videoRef.current.play().catch(() => {});\n }\n\n // AUDIO\n if (audioRef.current) {\n audioRef.current.srcObject = stream;\n audioRef.current.play().catch(() => {});\n }\n }, [participant?.media?.stream]);\n\n return {\n videoRef,\n audioRef,\n isCamActive: !!participant?.media?.camEnabled,\n isMicEnabled: !!participant?.media?.micEnabled,\n connectionState: participant?.connectionState,\n };\n};\n","import { useEffect, useState } from \"react\";\nimport { SDK_CONFIG } from \"../config/ws\";\n\ntype LiveRoomState = {\n active: boolean;\n count: number;\n canJoin: boolean;\n approved: boolean;\n isHost: boolean;\n hasMoreParticipants: boolean;\n participants: {\n id: string;\n name: string;\n isHost: boolean;\n isPresenter: boolean;\n micEnabled: boolean;\n camEnabled: boolean;\n }[];\n room?: {\n id: string;\n name: string;\n room_code: string;\n capacity: number;\n is_private: boolean;\n };\n};\n\n/**\n * Current SFU does not expose the old `/watch/:room` mesh presence socket.\n * Preview therefore uses the authoritative REST room endpoint and polls it.\n * Live participant/media state begins after JOIN over the SFU WebSocket.\n */\nexport function useMeetingPreview(roomId: string, participantId: string) {\n const [room, setRoom] = useState<LiveRoomState | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [isConnected, setIsConnected] = useState(false);\n const [isLoading, setIsLoading] = useState(true);\n\n useEffect(() => {\n if (!roomId) {\n setIsLoading(false);\n return;\n }\n\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n const load = async () => {\n try {\n const response = await fetch(\n `${SDK_CONFIG.apiBase}/rooms/${encodeURIComponent(roomId)}`,\n );\n\n if (!response.ok) {\n throw new Error(`Room lookup failed (${response.status})`);\n }\n\n const data = await response.json();\n if (stopped) return;\n\n setRoom({\n active: true,\n // The current REST room model intentionally does not expose a live\n // participant count. Do not fabricate one.\n count: 0,\n canJoin: !data.is_private,\n approved: false,\n isHost: false,\n hasMoreParticipants: false,\n participants: [],\n room: {\n id: data.id,\n name: data.name,\n room_code: data.room_code,\n capacity: data.capacity,\n is_private: data.is_private,\n },\n });\n setError(null);\n setIsConnected(true);\n setIsLoading(false);\n } catch (err: any) {\n if (stopped) return;\n setError(err?.message || \"Failed to load room\");\n setIsConnected(false);\n setIsLoading(false);\n } finally {\n if (!stopped) {\n timer = setTimeout(load, 5000);\n }\n }\n };\n\n void load();\n\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n };\n }, [roomId, participantId]);\n\n return {\n room,\n isConnected,\n isLoading,\n error,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,gBAAyD;;;ACAzD,IAAAC,gBAAkE;;;ACa3D,IAAM,aAAwB;AAAA,EACnC,SAAS;AAAA,EACT,QAAQ;AAAA;AAAA,EAER,YAAY;AAAA,IACV,EAAE,MAAM,CAAC,8BAA8B,EAAE;AAAA,IACzC,EAAE,MAAM,CAAC,+BAA+B,EAAE;AAAA,EAC5C;AAAA;AAAA,EAEA,mBAAmB;AAAA,EACnB,sBAAsB;AACxB;;;ACLO,IAAM,wBAAN,MAA4B;AAAA,EAgBjC,YAAY,UAAwC,CAAC,GAAG;AAfxD,SAAQ,eAAoC;AAE5C,SAAQ,WAAW,oBAAI,IAA0B;AAEjD,SAAQ,QAA+C;AASvD,SAAQ,cAAc;AAGpB,SAAK,aAAa,QAAQ,cAAc;AACxC,SAAK,YAAY,QAAQ,aAAa;AACtC,SAAK,mBAAmB,QAAQ,oBAAoB;AACpD,SAAK,YAAY,QAAQ,aAAa;AAEtC,SAAK,0BACH,QAAQ,4BAA4B,MAAM;AAAA,IAAC;AAAA,EAC/C;AAAA,EAEQ,qBAAmC;AACzC,QAAI,CAAC,KAAK,cAAc;AACtB,YAAM,oBACJ,OAAO,gBAEL,OAGA;AAEJ,UAAI,CAAC,mBAAmB;AACtB,cAAM,IAAI,MAAM,gDAAgD;AAAA,MAClE;AAEA,WAAK,eAAe,IAAI,kBAAkB;AAAA,IAC5C;AAEA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,SAAS;AACb,QAAI,CAAC,KAAK,aAAc;AAExB,QAAI,KAAK,aAAa,UAAU,aAAa;AAC3C,UAAI;AACF,cAAM,KAAK,aAAa,OAAO;AAAA,MACjC,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA,EAEA,SAAS,eAAuB,OAAyB;AACvD,QAAI,CAAC,cAAe;AAEpB,QAAI,MAAM,SAAS,QAAS;AAE5B,SAAK,kBAAkB,aAAa;AACpC,UAAM,UAAU,KAAK,mBAAmB;AACxC,UAAM,SAAS,IAAI,YAAY,CAAC,KAAK,CAAC;AACtC,UAAM,SAAS,QAAQ,wBAAwB,MAAM;AACrD,UAAM,WAAW,QAAQ,eAAe;AAExC,aAAS,UAAU;AACnB,aAAS,wBAAwB;AACjC,aAAS,cAAc;AACvB,aAAS,cAAc;AAEvB,WAAO,QAAQ,QAAQ;AAEvB,UAAM,OAAO,IAAI,aAAa,SAAS,OAAO;AAE9C,UAAM,QAAsB;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR,cAAc;AAAA,IAChB;AAEA,SAAK,SAAS,IAAI,eAAe,KAAK;AAEtC,UAAM;AAAA,MACJ;AAAA,MACA,MAAM;AACJ,aAAK,kBAAkB,aAAa;AAAA,MACtC;AAAA,MACA,EAAE,MAAM,KAAK;AAAA,IACf;AAEA,SAAK,MAAM;AAEX,SAAK,KAAK,OAAO;AAAA,EACnB;AAAA,EAEA,kBAAkB,eAAuB;AACvC,UAAM,QAAQ,KAAK,SAAS,IAAI,aAAa;AAE7C,QAAI,CAAC,MAAO;AAEZ,UAAM,SAAS;AAEf,QAAI;AACF,YAAM,OAAO,WAAW;AAAA,IAC1B,QAAQ;AAAA,IAER;AAEA,UAAM,OAAO,UAAU,EAAE,QAAQ,CAAC,UAAU;AAC1C,UAAI,UAAU,MAAM,OAAO;AACzB,cAAM,KAAK;AAAA,MACb;AAAA,IACF,CAAC;AAED,SAAK,SAAS,OAAO,aAAa;AAElC,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,YAAY,OAAyB;AACnC,eAAW,CAAC,eAAe,KAAK,KAAK,KAAK,UAAU;AAClD,UAAI,MAAM,UAAU,OAAO;AACzB,aAAK,kBAAkB,aAAa;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,QAAQ;AACN,eAAW,iBAAiB,KAAK,SAAS,KAAK,GAAG;AAChD,WAAK,kBAAkB,aAAa;AAAA,IACtC;AAEA,SAAK,SAAS,MAAM;AAEpB,SAAK,KAAK;AAEV,SAAK,cAAc,IAAI;AAAA,EACzB;AAAA,EAEA,QAAQ;AACN,QAAI,KAAK,MAAO;AAEhB,SAAK,QAAQ,YAAY,MAAM,KAAK,OAAO,GAAG,KAAK,UAAU;AAAA,EAC/D;AAAA,EAEA,OAAO;AACL,QAAI,CAAC,KAAK,MAAO;AAEjB,kBAAc,KAAK,KAAK;AACxB,SAAK,QAAQ;AAAA,EACf;AAAA,EAEQ,SAAS;AACf,UAAM,MAAM,YAAY,IAAI;AAE5B,eAAW,SAAS,KAAK,SAAS,OAAO,GAAG;AAC1C,UACE,MAAM,MAAM,eAAe,UAC3B,MAAM,MAAM,SACZ,CAAC,MAAM,MAAM,SACb;AACA,YAAI,MAAM,QAAQ;AAChB,gBAAM,SAAS;AAAA,QACjB;AAEA;AAAA,MACF;AAEA,YAAM,SAAS,uBAAuB,MAAM,IAAI;AAEhD,UAAI,aAAa;AAEjB,eAAS,IAAI,GAAG,IAAI,MAAM,KAAK,QAAQ,KAAK;AAC1C,cAAM,SAAS,MAAM,KAAK,CAAC;AAC3B,sBAAc,SAAS;AAAA,MACzB;AAEA,YAAM,MAAM,KAAK,KAAK,aAAa,MAAM,KAAK,MAAM;AAEpD,UAAI,CAAC,MAAM,QAAQ;AACjB,YAAI,OAAO,KAAK,WAAW;AACzB,gBAAM,SAAS;AACf,gBAAM,eAAe;AAAA,QACvB;AAAA,MACF,OAAO;AACL,YAAI,OAAO,KAAK,kBAAkB;AAChC,gBAAM,eAAe;AAAA,QACvB,WAAW,MAAM,MAAM,gBAAgB,KAAK,WAAW;AACrD,gBAAM,SAAS;AAAA,QACjB;AAAA,MACF;AAAA,IACF;AAEA,SAAK,cAAc;AAAA,EACrB;AAAA,EAEQ,sBAAgC;AACtC,WAAO,MAAM,KAAK,KAAK,SAAS,OAAO,CAAC,EACrC,OAAO,CAAC,YAAY,QAAQ,MAAM,EAClC,IAAI,CAAC,YAAY,QAAQ,aAAa;AAAA,EAC3C;AAAA,EAEQ,cAAc,QAAQ,OAAO;AACnC,UAAM,MAAM,KAAK,oBAAoB,EAAE,KAAK;AAE5C,UAAM,MAAM,IAAI,KAAK,GAAG;AAExB,QAAI,CAAC,SAAS,QAAQ,KAAK,aAAa;AACtC;AAAA,IACF;AAEA,SAAK,cAAc;AAEnB,SAAK,wBAAwB,GAAG;AAAA,EAClC;AAAA,EAEA,MAAM,UAAU;AACd,SAAK,MAAM;AAEX,QAAI,KAAK,cAAc;AACrB,UAAI;AACF,cAAM,KAAK,aAAa,MAAM;AAAA,MAChC,QAAQ;AAAA,MAER;AAEA,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AACF;;;ACnPO,IAAM,eAAN,MAAmB;AAAA,EAAnB;AACL,wBAAe,oBAAI,IAAyB;AAC5C,4BAAuC;AACvC,uBAAkC;AAClC,wBAAe,oBAAI,IAAyB;AAC5C,uBAA6B;AAC7B,4BAAmB,oBAAI,IAAY;AAEnC,SAAQ,YAAY,oBAAI,IAA+B;AAAA;AAAA;AAAA,EAIvD,UAAU,OAAmB,IAA0B;AACrD,QAAI,CAAC,KAAK,UAAU,IAAI,KAAK,GAAG;AAC9B,WAAK,UAAU,IAAI,OAAO,oBAAI,IAAI,CAAC;AAAA,IACrC;AACA,SAAK,UAAU,IAAI,KAAK,EAAG,IAAI,EAAE;AAEjC,WAAO,MAAM;AACX,WAAK,UAAU,IAAI,KAAK,GAAG,OAAO,EAAE;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,OAAO,OAAmB;AACxB,SAAK,UAAU,IAAI,KAAK,GAAG,QAAQ,CAAC,OAAO,GAAG,CAAC;AAAA,EACjD;AAAA,EAEA,eAAe,IAAmB;AAChC,QAAI,KAAK,gBAAgB,GAAI;AAC7B,SAAK,cAAc;AACnB,SAAK,OAAO,WAAW;AACvB,SAAK,OAAO,cAAc;AAAA,EAC5B;AAAA,EAEA,kBAAkB,KAAe;AAC/B,UAAM,OAAO,IAAI,IAAI,GAAG;AAExB,QACE,KAAK,SAAS,KAAK,iBAAiB,QACpC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,OAAO,KAAK,iBAAiB,IAAI,EAAE,CAAC,GACrD;AACA;AAAA,IACF;AAEA,SAAK,mBAAmB;AAExB,SAAK,OAAO,gBAAgB;AAAA,EAC9B;AAAA;AAAA,EAIA,eAAe,GAAgB;AAC7B,QAAI,KAAK,aAAa,IAAI,EAAE,EAAE,EAAG,QAAO;AAExC,UAAM,OAAO,IAAI,IAAI,KAAK,YAAY;AACtC,SAAK,IAAI,EAAE,IAAI,CAAC;AAChB,SAAK,eAAe;AAEpB,SAAK,OAAO,cAAc;AAC1B,WAAO;AAAA,EACT;AAAA,EAEA,kBAAkB,IAAY;AAE5B,UAAM,OAAO,IAAI,IAAI,KAAK,YAAY;AACtC,SAAK,OAAO,EAAE;AACd,SAAK,eAAe;AAEpB,SAAK,OAAO,cAAc;AAAA,EAC5B;AAAA,EAEA,uBACE,IACA,OACA;AACA,UAAM,IAAI,KAAK,aAAa,IAAI,EAAE;AAClC,QAAI,CAAC,EAAG;AAER,UAAM,UAAuB;AAAA,MAC3B,GAAG;AAAA,MACH,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,aAAa;AAAA,QACb,aAAa;AAAA,QACb,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,iBAAiB;AAAA,QACjB,GAAG,EAAE;AAAA,QACL,GAAG;AAAA,MACL;AAAA,IACF;AAGA,UAAM,OAAO,IAAI,IAAI,KAAK,YAAY;AACtC,SAAK,IAAI,IAAI,OAAO;AACpB,SAAK,eAAe;AAEpB,SAAK,OAAO,eAAe,EAAE,EAAE;AAC/B,SAAK,OAAO,cAAc;AAAA,EAC5B;AAAA,EAEA,uBAAuB,OAA8B;AACnD,UAAM,OAAO,KAAK;AAElB,QAAI,CAAC,MAAM;AACT,WAAK,mBAAmB;AAAA,QACtB,IAAI,MAAM,MAAM;AAAA,QAChB,MAAM,MAAM,QAAQ;AAAA,QACpB,OAAO;AAAA,UACL,QAAQ,MAAM,OAAO,UAAU;AAAA;AAAA,UAC/B,cAAc,MAAM,OAAO;AAAA,UAC3B,aAAa,MAAM,OAAO;AAAA,UAC1B,aAAa,MAAM,OAAO;AAAA,UAC1B,YAAY,MAAM,OAAO;AAAA,UACzB,YAAY,MAAM,OAAO,cAAc;AAAA,UACvC,YAAY,MAAM,OAAO,cAAc;AAAA,UACvC,iBAAiB,MAAM,OAAO,mBAAmB;AAAA,QACnD;AAAA,MACF;AAEA,WAAK,OAAO,kBAAkB;AAC9B;AAAA,IACF;AAEA,UAAM,YAAY,KAAK,SAAS;AAAA,MAC9B,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,aAAa;AAAA,MACb,aAAa;AAAA,MACb,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,iBAAiB;AAAA,IACnB;AAEA,UAAM,YAA8B;AAAA,MAClC,QAAQ,MAAM,OAAO,UAAU,UAAU;AAAA,MACzC,cAAc,MAAM,OAAO,gBAAgB,UAAU;AAAA,MACrD,aAAa,MAAM,OAAO,eAAe,UAAU;AAAA,MACnD,aAAa,MAAM,OAAO,eAAe,UAAU;AAAA,MACnD,YAAY,MAAM,OAAO,cAAc,UAAU;AAAA,MACjD,YAAY,MAAM,OAAO,cAAc,UAAU;AAAA,MACjD,YAAY,MAAM,OAAO,cAAc,UAAU;AAAA,MACjD,iBACE,MAAM,OAAO,mBAAmB,UAAU;AAAA,IAC9C;AAEA,SAAK,mBAAmB;AAAA,MACtB,GAAG;AAAA,MACH,IAAI,MAAM,MAAM,KAAK;AAAA,MACrB,MAAM,MAAM,QAAQ,KAAK;AAAA,MACzB,OAAO;AAAA,IACT;AAEA,SAAK,OAAO,kBAAkB;AAAA,EAChC;AAAA;AAAA,EAIA,eAAe,KAAkB;AAC/B,SAAK,aAAa,IAAI,IAAI,IAAI,GAAG;AACjC,SAAK,OAAO,MAAM;AAAA,EACpB;AAAA,EAEA,kBAAkB;AAChB,WAAO,MAAM,KAAK,KAAK,aAAa,OAAO,CAAC,EAAE;AAAA,MAC5C,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE;AAAA,IAC5B;AAAA,EACF;AAAA,EAEA,YAAY;AACV,SAAK,aAAa,MAAM;AACxB,SAAK,OAAO,MAAM;AAAA,EACpB;AAAA;AAAA,EAIA,kBAAkB;AAChB,WAAO,MAAM,KAAK,KAAK,aAAa,OAAO,CAAC;AAAA,EAC9C;AAAA,EAEA,eAAe,IAAY;AACzB,WAAO,KAAK,aAAa,IAAI,EAAE,KAAK;AAAA,EACtC;AAAA,EAEA,mBAAmB;AACjB,SAAK,aAAa,MAAM;AACxB,SAAK,aAAa,MAAM;AACxB,SAAK,cAAc;AACnB,SAAK,mBAAmB,oBAAI,IAAI;AAChC,SAAK,OAAO,cAAc;AAC1B,SAAK,OAAO,MAAM;AAClB,SAAK,OAAO,WAAW;AACvB,SAAK,OAAO,gBAAgB;AAAA,EAC9B;AACF;;;ACxHO,IAAM,YAAN,MAAgB;AAAA,EAuHrB,YAAY,UAA4B,CAAC,GAAG;AAlH5C,SAAQ,KAAuB;AAC/B,SAAQ,YAAsC;AAC9C,SAAQ,aAAuC;AAE/C,SAAQ,cAAkC;AAC1C,SAAQ,eAAmC;AAC3C,SAAQ,cAAmC;AAC3C,SAAQ,cAAmC;AAC3C,SAAQ,eAAoC;AAC5C,SAAQ,mBAA6C;AACrD,SAAQ,oBAA8C;AACtD,SAAQ,oBAA8C;AAEtD,SAAQ,aAA6B,CAAC;AACtC,SAAQ,YAAY;AACpB,SAAQ,oBAAoB;AAC5B,SAAQ,wBAAwB;AAChC,SAAQ,uBAAsC;AAC9C,SAAQ,QAAuB;AAC/B,SAAQ,OAAsB;AAC9B,SAAQ,cAA6B;AACrC,SAAQ,uBAAsC;AAC9C,SAAQ,cAGJ,CAAC;AAEL,SAAQ,QAA4B;AACpC,SAAQ,mBAAmB;AAC3B,SAAQ,oBAAoB;AAC5B,SAAQ,oBAAoB;AAC5B,SAAQ,oBAAoB;AAC5B,SAAQ,oBAAoB;AAC5B,SAAQ,iBAAuD;AAC/D,SAAQ,mBAAmB;AAC3B,SAAQ,uBAAuB;AAC/B,SAAQ,kBAAkB;AAC1B,SAAQ,aAAgC;AAExC,SAAQ,8BAA8B;AACtC,SAAQ,yBAA+D;AAEvE,SAAQ,aAAsD;AAAA,MAC5D,WAAW,CAAC;AAAA,MACZ,YAAY,CAAC;AAAA,IACf;AAEA,SAAQ,wBAAwB;AAChC,SAAQ,aAAoB,CAAC;AAC7B,SAAQ,oBAA8B,CAAC;AACvC,SAAQ,sBAAsB;AAC9B,SAAQ,sBAIH,CAAC;AAEN,SAAQ,mBAAmB,oBAAI,IAAY;AAC3C,SAAQ,gBAAgB,oBAAI,IAAuB;AACnD,SAAQ,eAAe,oBAAI,IAA6B;AACxD,SAAQ,gBAAgB,oBAAI,IAAyB;AACrD,SAAQ,sBAAsB,oBAAI,IAAyB;AAC3D,SAAQ,qBAAqB,oBAAI,IAAoB;AACrD,SAAQ,gBAAgB,oBAAI,IAAoB;AAChD,SAAQ,gBAAgB,oBAAI,IAA2C;AAEvE,SAAQ,uBAA8D;AAiFtE,SAAQ,iBAAwD;AAhC9D,SAAK,UAAU,QAAQ,WAAW;AAClC,SAAK,SAAS,QAAQ,UAAU;AAChC,SAAK,gBAAgB,QAAQ,iBAAiB,KAAK,SAAS;AAE5D,SAAK,gBAAgB,QAAQ,kBAAkB,MAAM;AAAA,IAAC;AACtD,SAAK,sBAAsB,QAAQ,wBAAwB,MAAM;AAAA,IAAC;AAClE,SAAK,oBAAoB,QAAQ,sBAAsB,MAAM;AAAA,IAAC;AAC9D,SAAK,wBAAwB,QAAQ,0BAA0B,MAAM;AAAA,IAAC;AACtE,SAAK,mBAAmB,QAAQ,qBAAqB,MAAM;AAAA,IAAC;AAC5D,SAAK,qBAAqB,QAAQ,uBAAuB,MAAM;AAAA,IAAC;AAChE,SAAK,gBAAgB,QAAQ,kBAAkB,MAAM;AAAA,IAAC;AACtD,SAAK,cAAc,QAAQ,gBAAgB,MAAM;AAAA,IAAC;AAClD,SAAK,iBAAiB,QAAQ,mBAAmB,MAAM;AAAA,IAAC;AACxD,SAAK,iBAAiB,QAAQ,mBAAmB,MAAM;AAAA,IAAC;AACxD,SAAK,gBAAgB,QAAQ,kBAAkB,MAAM;AAAA,IAAC;AACtD,SAAK,iBAAiB,QAAQ,mBAAmB,MAAM;AAAA,IAAC;AACxD,SAAK,iBAAiB,QAAQ,mBAAmB,MAAM;AAAA,IAAC;AACxD,SAAK,kBAAkB,QAAQ,oBAAoB,MAAM;AAAA,IAAC;AAC1D,SAAK,uBAAuB,QAAQ,yBAAyB,MAAM;AAAA,IAAC;AACpE,SAAK,uBAAuB,QAAQ,yBAAyB,MAAM;AAAA,IAAC;AACpE,SAAK,sBAAsB,QAAQ,wBAAwB,MAAM;AAAA,IAAC;AAClE,SAAK,qBAAqB,QAAQ,uBAAuB,MAAM;AAAA,IAAC;AAChE,SAAK,qBAAqB,QAAQ,uBAAuB,MAAM;AAAA,IAAC;AAChE,SAAK,UAAU,QAAQ,WAAW,QAAQ;AAC1C,SAAK,gBAAgB,QAAQ,kBAAkB,MAAM;AAAA,IAAC;AACtD,SAAK,aAAa,QAAQ,eAAe,MAAM;AAAA,IAAC;AAChD,SAAK,eAAe,QAAQ,iBAAiB,MAAM;AAAA,IAAC;AACpD,SAAK,0BACH,QAAQ,4BAA4B,MAAM;AAAA,IAAC;AAC7C,SAAK,gBAAgB,QAAQ,kBAAkB;AAAA,EACjD;AAAA,EAIQ,iBAAiB;AACvB,SAAK,cAAc;AAEnB,SAAK,iBAAiB,YAAY,MAAM;AACtC,UAAI,KAAK,IAAI,eAAe,UAAU,KAAM;AAE5C,WAAK,KAAK;AAAA,QACR,MAAM;AAAA,QACN,SAAS;AAAA,UACP,OAAO,OAAO,WAAW;AAAA,QAC3B;AAAA,MACF,CAAC;AAAA,IACH,GAAG,GAAM;AAAA,EACX;AAAA,EAEQ,gBAAgB;AACtB,QAAI,KAAK,gBAAgB;AACvB,oBAAc,KAAK,cAAc;AACjC,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,WAAmB;AACzB,WAAO,OAAO,WAAW,eAAe,OAAO,aAC3C,OAAO,WAAW,IAClB,MAAM,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC;AAAA,EAC7D;AAAA,EAEQ,iBAAiB,UAAkB;AACzC,WAAO,sBAAsB,QAAQ;AAAA,EACvC;AAAA,EAEQ,gBAAgB,UAAiC;AACvD,QAAI;AACF,aAAO,aAAa,QAAQ,KAAK,iBAAiB,QAAQ,CAAC;AAAA,IAC7D,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,gBAAgB,UAAkB,OAAe;AACvD,QAAI;AACF,mBAAa,QAAQ,KAAK,iBAAiB,QAAQ,GAAG,KAAK;AAAA,IAC7D,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,iBAAiB,UAAyB;AAChD,QAAI,CAAC,SAAU;AACf,QAAI;AACF,mBAAa,WAAW,KAAK,iBAAiB,QAAQ,CAAC;AAAA,IACzD,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,SAAS,MAA0B;AACzC,QAAI,KAAK,UAAU,KAAM;AACzB,SAAK,QAAQ;AACb,SAAK,cAAc,IAAI;AAAA,EACzB;AAAA,EAEA,qBAAyC;AACvC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,mBAAkC;AAChC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,iBAAgC;AAC9B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,iBAAqC;AACnC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,kBAAsC;AACpC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,sBAAsB,eAA2C;AAC/D,WAAO,KAAK,oBAAoB,IAAI,aAAa,KAAK;AAAA,EACxD;AAAA,EAEA,eAAe,QAA4B;AACzC,SAAK,cAAc;AAAA,EACrB;AAAA,EAEQ,gBAAwB;AAC9B,YAAQ,EAAE,KAAK,WAAW,SAAS;AAAA,EACrC;AAAA,EAEA,MAAc,QAAQ,KAAa,UAAuB,CAAC,GAAG;AAC5D,UAAM,MAAM,MAAM,MAAM,KAAK;AAAA,MAC3B,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,GAAG;AAAA,IACL,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACX,UAAI,OAAY,CAAC;AACjB,UAAI;AACF,eAAO,MAAM,IAAI,KAAK;AAAA,MACxB,QAAQ;AAAA,MAER;AACA,YAAM,IAAI,MAAM,KAAK,WAAW,IAAI,UAAU;AAAA,IAChD;AAEA,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA,EAEA,MAAM,WAAW,OAKd;AACD,WAAO,KAAK,QAAQ,GAAG,KAAK,OAAO,UAAU;AAAA,MAC3C,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU;AAAA,QACnB,MAAM,MAAM;AAAA,QACZ,aAAa,MAAM,eAAe;AAAA,QAClC,UAAU,MAAM,YAAY;AAAA,QAC5B,YAAY,MAAM,cAAc;AAAA,MAClC,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QAAQ,UAAkB;AAC9B,WAAO,KAAK;AAAA,MACV,GAAG,KAAK,OAAO,UAAU,mBAAmB,QAAQ,CAAC;AAAA,IACvD;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,UAAkB;AACjC,WAAO,KAAK;AAAA,MACV,GAAG,KAAK,OAAO,UAAU,mBAAmB,QAAQ,CAAC;AAAA,MACrD;AAAA,QACE,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,SACJ,UACA,UAMI,CAAC,GACL;AACA,UAAM,WAAW,SAAS,KAAK;AAC/B,QAAI,KAAK,QAAQ,KAAK,SAAS,UAAU;AACvC,WAAK,cAAc;AAAA,IACrB;AAEA,SAAK,OAAO;AACZ,SAAK,cAAc;AAAA,MACjB,aAAa,QAAQ;AAAA,MACrB,WAAW,QAAQ;AAAA,IACrB;AACA,QAAI,QAAQ,cAAe,MAAK,gBAAgB,QAAQ;AACxD,QAAI,OAAO,QAAQ,eAAe;AAChC,WAAK,oBAAoB,QAAQ;AACnC,QAAI,OAAO,QAAQ,eAAe;AAChC,WAAK,oBAAoB,QAAQ;AACnC,QAAI,CAAC,KAAK,aAAa;AACrB,WAAK,cAAc,KAAK,gBAAgB,KAAK,IAAI;AAAA,IACnD;AAEA,UAAM,OAAO,MAAM,KAAK,QAAQ,GAAG,KAAK,OAAO,UAAU;AAAA,MACvD,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU;AAAA,QACnB,WAAW,KAAK;AAAA,QAChB,SAAS,KAAK;AAAA,QACd,cAAc,QAAQ;AAAA,QACtB,YAAY,QAAQ;AAAA,MACtB,CAAC;AAAA,IACH,CAAC;AAED,SAAK,QAAQ,MAAM;AACnB,QAAI,CAAC,KAAK,MAAO,OAAM,IAAI,MAAM,kCAAkC;AAEnE,WAAO,KAAK,QAAQ,KAAK,OAAO,KAAK,WAAW;AAAA,EAClD;AAAA,EAEA,MAAc,qBAAqB;AACjC,QAAI,CAAC,KAAK,KAAM,OAAM,IAAI,MAAM,qCAAqC;AAErE,UAAM,OAAO,MAAM,KAAK,QAAQ,GAAG,KAAK,OAAO,UAAU;AAAA,MACvD,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU;AAAA,QACnB,WAAW,KAAK;AAAA,QAChB,SAAS,KAAK;AAAA,QACd,cAAc,KAAK,YAAY;AAAA,QAC/B,YAAY,KAAK,YAAY;AAAA,MAC/B,CAAC;AAAA,IACH,CAAC;AAED,QAAI,CAAC,MAAM,MAAO,OAAM,IAAI,MAAM,iCAAiC;AACnE,SAAK,QAAQ,KAAK;AAClB,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,QAAQ,OAAe,UAAe,CAAC,GAAG;AAChD,SAAK,QAAQ;AACb,SAAK,mBAAmB;AACxB,SAAK,SAAS,KAAK,mBAAmB,IAAI,iBAAiB,YAAY;AAEvE,WAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC5C,WAAK,aAAa,EAAE,SAAS,OAAO;AACpC,WAAK,cAAc,OAAO;AAAA,IAC5B,CAAC;AAAA,EACH;AAAA,EAEQ,cAAc,UAAe,CAAC,GAAG;AACvC,QAAI,CAAC,KAAK,SAAS,CAAC,KAAK,MAAM;AAC7B,YAAM,QAAQ,IAAI,MAAM,uCAAuC;AAC/D,WAAK,SAAS,KAAK;AACnB;AAAA,IACF;AAEA,QAAI,KAAK,IAAI;AACX,UAAI;AACF,aAAK,GAAG,UAAU;AAClB,aAAK,GAAG,MAAM;AAAA,MAChB,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,KAAK,IAAI;AAAA,MACb,GAAG,KAAK,MAAM,iBAAiB,mBAAmB,KAAK,KAAK,CAAC;AAAA,IAC/D;AACA,SAAK,KAAK;AAEV,OAAG,SAAS,MAAM;AAChB,WAAK,eAAe;AACpB,WAAK,SAAS,SAAS;AACvB,WAAK,oBAAoB,QAAQ,KAAK,WAAW;AAEjD,YAAM,cAAmB;AAAA,QACvB,OAAO,KAAK;AAAA,QACZ,WAAW,KAAK;AAAA,QAChB,cAAc,KAAK;AAAA,QACnB,cAAc,QAAQ;AAAA,QACtB,YAAY,QAAQ;AAAA,QACpB,aAAa,KAAK;AAAA,QAClB,aAAa,KAAK;AAAA,MACpB;AAGA,UAAI,KAAK,sBAAsB;AAC7B,aAAK,KAAK;AAAA,UACR,MAAM;AAAA,UACN,YAAY,KAAK;AAAA,UACjB,SAAS;AAAA,QACX,CAAC;AAAA,MACH,OAAO;AACL,aAAK,KAAK,EAAE,MAAM,QAAQ,SAAS,YAAY,CAAC;AAAA,MAClD;AAAA,IACF;AAEA,OAAG,UAAU,CAAC,UAAU;AACtB,WAAK,QAAQ,KAAK;AAAA,IACpB;AAEA,OAAG,UAAU,MAAM;AACjB,WAAK,cAAc;AACnB,UAAI,KAAK,OAAO,GAAI;AACpB,WAAK,KAAK;AAEV,UAAI,KAAK,oBAAoB,KAAK,UAAU,WAAW;AACrD,aAAK,SAAS,cAAc;AAC5B,aAAK,eAAe;AACpB;AAAA,MACF;AAGA,WAAK,SAAS,cAAc;AAC5B,WAAK,eAAe;AACpB,WAAK,kBAAkB;AAAA,IACzB;AAEA,OAAG,YAAY,OAAO,UAAU;AAC9B,UAAI,KAAK,OAAO,GAAI;AACpB,UAAI;AACF,cAAM,UAAU,KAAK,MAAM,MAAM,IAAI;AACrC,cAAM,KAAK,oBAAoB,OAAO;AAAA,MACxC,SAAS,OAAO;AACd,aAAK,QAAQ,KAAK;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,oBAAoB;AAC1B,QAAI,KAAK,kBAAkB,KAAK,iBAAkB;AAClD,QAAI,KAAK,oBAAoB,KAAK,sBAAsB;AACtD,WAAK,SAAS,cAAc;AAC5B,WAAK,SAAS,IAAI,MAAM,kCAAkC,CAAC;AAC3D;AAAA,IACF;AAEA,SAAK,oBAAoB;AACzB,UAAM,QAAQ,KAAK;AAAA,MACjB;AAAA,MACA,KAAK,kBAAkB,KAAK,IAAI,GAAG,KAAK,mBAAmB,CAAC;AAAA,IAC9D;AAEA,SAAK,eAAe,KAAK,gBAAgB;AAEzC,SAAK,iBAAiB,WAAW,YAAY;AAC3C,WAAK,iBAAiB;AACtB,UAAI;AACF,cAAM,KAAK,mBAAmB;AAC9B,aAAK,cAAc,KAAK,WAAW;AAAA,MACrC,SAAS,OAAO;AACd,aAAK,QAAQ,KAAK;AAClB,aAAK,kBAAkB;AAAA,MACzB;AAAA,IACF,GAAG,KAAK;AAAA,EACV;AAAA,EAEQ,SAAS,OAAY;AAC3B,QAAI,KAAK,YAAY;AACnB,YAAM,SAAS,KAAK;AACpB,WAAK,aAAa;AAClB,aAAO,OAAO,KAAK;AAAA,IACrB;AAAA,EACF;AAAA,EAEQ,YAAY,OAAY;AAC9B,QAAI,CAAC,KAAK,WAAY;AACtB,UAAM,SAAS,KAAK;AACpB,SAAK,aAAa;AAClB,WAAO,QAAQ,KAAK;AAAA,EACtB;AAAA,EAEA,MAAc,oBAAoB,SAAc;AAC9C,UAAM,OAAO,SAAS;AACtB,UAAM,UAAU,SAAS,WAAW,CAAC;AAErC,YAAQ,MAAM;AAAA,MACZ,KAAK,UAAU;AACb,cAAM,KAAK,aAAa,OAAO;AAC/B;AAAA,MACF;AAAA,MAEA,KAAK,QAAQ;AACX,aAAK,oBAAoB;AACzB;AAAA,MACF;AAAA,MAEA,KAAK,gBAAgB;AACnB,cAAM,YAAY,QAAQ,cAAc,QAAQ;AAChD,YAAI,CAAC,UAAW,OAAM,IAAI,MAAM,gCAAgC;AAEhE,aAAK,uBAAuB;AAC5B,aAAK,SAAS,kBAAkB;AAChC,aAAK,cAAc;AAAA,UACjB,YAAY;AAAA,UACZ,WAAW,QAAQ,aAAa,KAAK,QAAQ;AAAA,UAC7C,SAAS,QAAQ;AAAA,QACnB,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,iBAAiB;AACpB,cAAM,YAAY,QAAQ,cAAc,QAAQ;AAChD,YAAI,CAAC,UAAW;AAChB,aAAK,uBAAuB;AAC5B,aAAK,eAAe,SAAS;AAI7B,YAAI,KAAK,IAAI,eAAe,UAAU,MAAM;AAC1C,eAAK,SAAS,SAAS;AACvB,eAAK,KAAK;AAAA,YACR,MAAM;AAAA,YACN,YAAY;AAAA,YACZ,SAAS;AAAA,cACP,OAAO,KAAK;AAAA,cACZ,WAAW,KAAK;AAAA,cAChB,cAAc,KAAK;AAAA,cACnB,cAAc,KAAK,YAAY;AAAA,cAC/B,YAAY,KAAK,YAAY;AAAA,YAC/B;AAAA,UACF,CAAC;AAAA,QACH;AACA;AAAA,MACF;AAAA,MAEA,KAAK,iBAAiB;AACpB,cAAM,YAAY,QAAQ,cAAc,QAAQ;AAChD,cAAM,SAAS,QAAQ;AACvB,aAAK,eAAe,WAAW,MAAM;AACrC,aAAK,uBAAuB;AAC5B,aAAK,mBAAmB;AACxB,aAAK,SAAS,IAAI,MAAM,UAAU,uBAAuB,CAAC;AAC1D;AAAA,MACF;AAAA,MAEA,KAAK;AAAA,MACL,KAAK,gBAAgB;AACnB,aAAK,gBAAgB,QAAQ,WAAW,OAAO;AAC/C;AAAA,MACF;AAAA,MAEA,KAAK,kBAAkB;AACrB,YAAI,CAAC,KAAK,UAAW;AACrB,cAAM,KAAK,UAAU,qBAAqB;AAAA,UACxC,MAAM;AAAA,UACN,KAAK,QAAQ;AAAA,QACf,CAAC;AACD,cAAM,KAAK,gBAAgB,WAAW;AACtC;AAAA,MACF;AAAA,MAEA,KAAK,mBAAmB;AACtB,aAAK,WAAW,KAAK,OAAO;AAC5B,YAAI,CAAC,KAAK,sBAAuB,OAAM,KAAK,kBAAkB;AAC9D;AAAA,MACF;AAAA,MAEA,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,4BAA4B;AAC/B,cAAM,mBAAmB;AAAA,UACvB,GAAG;AAAA,UACH,MACE,QAAQ,SACP,SAAS,4BAA4B,cAAc;AAAA,QACxD;AACA,cAAM,KAAK,UAAU,gBAAgB;AACrC;AAAA,MACF;AAAA,MAEA,KAAK,sBAAsB;AACzB,cAAM,cAAc,QAAQ,eAAe;AAC3C,cAAM,gBACJ,aAAa,kBAAkB,QAAQ;AACzC,YAAI,CAAC,iBAAiB,kBAAkB,KAAK;AAC3C;AAEF,YAAI,YAAa,MAAK,aAAa,IAAI,eAAe,WAAW;AACjE,aAAK,oBAAoB,WAAW;AACpC;AAAA,MACF;AAAA,MAEA,KAAK,oBAAoB;AACvB,cAAM,gBAAgB,QAAQ;AAC9B,YAAI,CAAC,cAAe;AACpB,aAAK,aAAa,OAAO,aAAa;AACtC,aAAK,wBAAwB,aAAa;AAC1C,aAAK,kBAAkB,aAAa;AACpC;AAAA,MACF;AAAA,MAEA,KAAK,2BAA2B;AAC9B,cAAM,gBAAgB,QAAQ;AAC9B,YAAI,CAAC,cAAe;AACpB,aAAK;AAAA,UACH;AAAA,UACA,QAAQ,QAAQ,WAAW;AAAA,UAC3B,QAAQ,QAAQ,WAAW;AAAA,QAC7B;AACA;AAAA,MACF;AAAA,MAEA,KAAK;AAAA,MACL,KAAK,gCAAgC;AACnC,cAAM,gBAAgB,QAAQ;AAC9B,cAAM,WAAW,QAAQ;AACzB,YAAI,iBAAiB,UAAU;AAC7B,eAAK,sBAAsB,eAAe,OAAO,QAAQ,CAAC;AAAA,QAC5D;AACA;AAAA,MACF;AAAA,MAEA,KAAK,mBAAmB;AACtB,cAAM,QAAmB,QAAQ,SAAS;AAC1C,YAAI,CAAC,OAAO,SAAU;AACtB,aAAK,cAAc,KAAK;AAExB,YAAI,MAAM,mBAAmB,KAAK,sBAAsB;AACtD,cAAI,MAAM,WAAW,SAAS;AAC5B,iBAAK,cAAc,IAAI,SAAS,MAAM,QAAQ;AAC9C,kBAAM,QAAQ,EACZ,KAAK,aAAa,eAAe,EAAE,CAAC,GAAG,WAAW;AAEpD,iBAAK,KAAK;AAAA,cACR,MAAM;AAAA,cACN,SAAS,EAAE,UAAU,MAAM,UAAU,MAAM;AAAA,YAC7C,CAAC;AAAA,UACH;AACA,cAAI,MAAM,WAAW,UAAU;AAC7B,iBAAK,cAAc,IAAI,UAAU,MAAM,QAAQ;AAC/C,kBAAM,QAAQ,EACZ,KAAK,aAAa,eAAe,EAAE,CAAC,GAAG,WAAW;AAEpD,iBAAK,KAAK;AAAA,cACR,MAAM;AAAA,cACN,SAAS,EAAE,UAAU,MAAM,UAAU,MAAM;AAAA,YAC7C,CAAC;AAAA,UACH;AACA,cAAI,MAAM,WAAW;AACnB,iBAAK,cAAc,IAAI,UAAU,MAAM,QAAQ;AACjD;AAAA,QACF;AAEA,aAAK,iBAAiB,KAAK;AAC3B,YAAI,KAAK,cAAe,OAAM,KAAK,UAAU,MAAM,QAAQ;AAC3D;AAAA,MACF;AAAA,MAEA,KAAK,qBAAqB;AACxB,cAAM,UAAU,QAAQ,YAAY,QAAQ,OAAO;AACnD,YAAI,CAAC,QAAS;AACd,cAAM,QACJ,KAAK,cAAc,IAAI,OAAO,KAC7B;AAAA,UACC,UAAU;AAAA,UACV,gBAAgB,KAAK,mBAAmB,IAAI,OAAO,KAAK;AAAA,UACxD,QAAQ,KAAK,cAAc,IAAI,OAAO;AAAA,UACtC,MAAM;AAAA,QACR;AAEF,aAAK,cAAc,OAAO,OAAO;AACjC,aAAK,iBAAiB,OAAO,OAAO;AACpC,aAAK,mBAAmB,OAAO,OAAO;AACtC,aAAK,cAAc,OAAO,OAAO;AAEjC,mBAAW,CAAC,QAAQ,OAAO,KAAK,KAAK,eAAe;AAClD,cAAI,YAAY,QAAS,MAAK,cAAc,OAAO,MAAM;AAAA,QAC3D;AAEA,YAAI,MAAM,mBAAmB,KAAK,qBAAsB;AACxD,aAAK,mBAAmB,KAAK;AAC7B;AAAA,MACF;AAAA,MAEA,KAAK,uBAAuB;AAC1B,cAAM,UAAU,QAAQ,YAAY,QAAQ,OAAO;AACnD,YAAI,CAAC,QAAS;AAEd,cAAM,WAAW,KAAK,cAAc,IAAI,OAAO;AAC/C,cAAM,QAAmB;AAAA,UACvB,GAAI,YAAY,CAAC;AAAA,UACjB,GAAI,QAAQ,SAAS,CAAC;AAAA,UACtB,UAAU;AAAA,UACV,gBACE,QAAQ,kBACR,UAAU,kBACV,QAAQ,OAAO;AAAA,UACjB,MACE,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,UAAU,QAAQ;AAAA,UAC3D,QAAQ,QAAQ,UAAU,QAAQ,OAAO,UAAU,UAAU;AAAA,UAC7D,OAAO,QAAQ,QAAQ,KAAK;AAAA,QAC9B;AAEA,YAAI,CAAC,MAAM,eAAgB;AAC3B,aAAK,cAAc,KAAK;AACxB,aAAK,oBAAoB,KAAK;AAC9B;AAAA,MACF;AAAA,MAEA,KAAK,wBAAwB;AAE3B;AAAA,MACF;AAAA,MAEA,KAAK,qBAAqB;AACxB,aAAK,mBAAmB;AAAA,UACtB,cAAc,QAAQ;AAAA,UACtB,YAAY,QAAQ;AAAA,QACtB,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,qBAAqB;AACxB,aAAK,mBAAmB;AAAA,UACtB,cAAc,QAAQ;AAAA,UACtB,YAAY,QAAQ;AAAA,QACtB,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,gBAAgB;AACnB,aAAK,SAAS,cAAc;AAC5B;AAAA,MACF;AAAA,MAEA,KAAK,wBAAwB;AAC3B,cAAM,gBAAgB,QAAQ;AAC9B,cAAM,QAAQ,QAAQ;AACtB,YAAI,MAAO,MAAK,cAAc,KAAK;AACnC,YAAI,cAAe,MAAK,qBAAqB,eAAe,KAAK;AACjE;AAAA,MACF;AAAA,MAEA,KAAK,wBAAwB;AAC3B,cAAM,gBAAgB,QAAQ;AAC9B,cAAM,UAAU,QAAQ;AAIxB,aAAK,qBAAqB,eAAe,OAAO;AAChD;AAAA,MACF;AAAA,MAEA,KAAK,cAAc;AACjB,cAAM,eAAe,QAAQ,gBAAgB,CAAC;AAC9C,aAAK,sBAAsB,OAAO;AAClC,aAAK,aAAa,OAAO;AACzB,mBAAW,eAAe,cAAc;AACtC,gBAAM,MAAM,aAAa;AACzB,cAAI,CAAC,IAAK;AACV,cAAI,QAAQ,KAAK,sBAAsB;AACrC,iBAAK,aAAa,IAAI,KAAK,WAAW;AACtC,iBAAK;AAAA,cACH;AAAA,cACA,OAAO,YAAY,YAAY,WAAW;AAAA,YAC5C;AACA,iBAAK;AAAA,cACH;AAAA,cACA,QAAQ,YAAY,WAAW;AAAA,cAC/B,QAAQ,YAAY,WAAW;AAAA,YACjC;AAAA,UACF;AAAA,QACF;AACA,mBAAW,CAAC,GAAG,KAAK,KAAK,cAAc;AACrC,cAAI,CAAC,aAAa,KAAK,CAAC,MAAW,GAAG,mBAAmB,GAAG,GAAG;AAC7D,iBAAK,aAAa,OAAO,GAAG;AAC5B,iBAAK,wBAAwB,GAAG;AAChC,iBAAK,kBAAkB,GAAG;AAAA,UAC5B;AAAA,QACF;AACA,mBAAW,SAAS,QAAQ,UAAU,CAAC,EAAG,MAAK,cAAc,KAAK;AAClE,YAAI,MAAM,QAAQ,QAAQ,YAAY,GAAG;AACvC,qBAAWC,YAAW,QAAQ;AAC5B,iBAAK,cAAcA,QAAO;AAAA,QAC9B;AACA;AAAA,MACF;AAAA,MAEA,KAAK,gBAAgB;AACnB,cAAM,MAAM,QAAQ,WAAW;AAC/B,YAAI,KAAK,GAAI,MAAK,cAAc,GAAG;AACnC;AAAA,MACF;AAAA,MAEA,KAAK,YAAY;AACf,cAAM,WAAW,QAAQ,YAAY;AACrC,YAAI,UAAU,MAAM,UAAU,MAAO,MAAK,WAAW,QAAQ;AAC7D;AAAA,MACF;AAAA,MAEA,KAAK,SAAS;AACZ,cAAMA,WAAU,QAAQ,WAAW;AACnC,YACE,KAAK,UAAU,kBACfA,SAAQ,SAAS,8BAA8B,GAC/C;AACA,kBAAQ;AAAA,YACN;AAAA,YACAA;AAAA,UACF;AACA;AAAA,QACF;AACA,cAAM,QAAQ,IAAI,MAAMA,QAAO;AAC/B,YAAI,KAAK,UAAU,aAAa,KAAK,UAAU,oBAAoB;AACjE,eAAK,QAAQ,KAAK;AAClB,eAAK,SAAS,KAAK;AACnB;AAAA,QACF;AACA,aAAK,QAAQ,KAAK;AAClB;AAAA,MACF;AAAA,MAEA;AACE,gBAAQ,MAAM,yCAAyC,OAAO;AAAA,IAClE;AAAA,EACF;AAAA,EAEQ,sBAAsB,SAAc;AAC1C,UAAM,eAAe,QAAQ,gBAAgB,CAAC;AAC9C,UAAM,QAAQ,aAAa;AAAA,MACzB,CAAC,MAAW,GAAG,mBAAmB,KAAK;AAAA,IACzC;AACA,QAAI,OAAO;AACT,WAAK,oBAAoB,QAAQ,MAAM,WAAW;AAClD,WAAK,oBAAoB,QAAQ,MAAM,WAAW;AAAA,IACpD;AAAA,EACF;AAAA,EAEQ,cAAc,OAAkB;AACtC,SAAK,cAAc,IAAI,MAAM,UAAU,KAAK;AAC5C,SAAK,mBAAmB,IAAI,MAAM,UAAU,MAAM,cAAc;AAChE,QAAI,MAAM,OAAQ,MAAK,cAAc,IAAI,MAAM,UAAU,MAAM,MAAM;AAAA,EACvE;AAAA,EAEA,MAAc,aAAa,SAAc;AACvC,UAAM,UAAU,KAAK;AACrB,SAAK,oBAAoB;AAEzB,SAAK,aAAa,QAAQ,eAAe,KAAK,cAAc,CAAC;AAC7D,SAAK,uBAAuB,QAAQ;AACpC,SAAK,cACH,QAAQ,gBAAgB,QAAQ,eAAe,KAAK;AACtD,QAAI,KAAK,QAAQ,KAAK,aAAa;AACjC,WAAK,gBAAgB,KAAK,MAAM,KAAK,WAAW;AAAA,IAClD;AACA,SAAK,uBAAuB;AAC5B,SAAK,mBAAmB;AAExB,SAAK,aAAa,MAAM;AACxB,SAAK,cAAc,MAAM;AACzB,SAAK,mBAAmB,MAAM;AAC9B,SAAK,cAAc,MAAM;AACzB,SAAK,cAAc,MAAM;AAEzB,eAAW,eAAe,QAAQ,gBAAgB,CAAC,GAAG;AACpD,UAAI,aAAa,gBAAgB;AAC/B,aAAK,aAAa,IAAI,YAAY,gBAAgB,WAAW;AAAA,MAC/D;AAAA,IACF;AAEA,eAAW,SAAS,QAAQ,UAAU,CAAC,GAAG;AACxC,UAAI,OAAO,SAAU,MAAK,cAAc,KAAK;AAAA,IAC/C;AAEA,UAAM,KAAK,0BAA0B;AACrC,SAAK,SAAS,WAAW;AACzB,SAAK,YAAY,SAAS,OAAO;AAEjC,eAAW,eAAe,KAAK,aAAa,OAAO,GAAG;AACpD,UAAI,YAAY,mBAAmB,KAAK,sBAAsB;AAC5D,aAAK,oBAAoB,WAAW;AACpC,aAAK;AAAA,UACH,YAAY;AAAA,UACZ,OAAO,YAAY,YAAY,WAAW;AAAA,QAC5C;AACA,aAAK;AAAA,UACH,YAAY;AAAA,UACZ,QAAQ,YAAY,WAAW;AAAA,UAC/B,QAAQ,YAAY,WAAW;AAAA,QACjC;AAAA,MACF;AAAA,IACF;AAEA,QAAI,MAAM,QAAQ,QAAQ,YAAY,GAAG;AACvC,iBAAW,WAAW,QAAQ,aAAc,MAAK,cAAc,OAAO;AAAA,IACxE;AACA,SAAK,aAAa,OAAO;AAIzB,QAAI,KAAK,aAAa;AACpB,YAAM,KAAK,sBAAsB;AAAA,IACnC;AAEA,QAAI,KAAK,eAAe;AACtB,YAAM,WAAW,CAAC,GAAG,KAAK,cAAc,OAAO,CAAC,EAC7C,OAAO,CAAC,UAAU,MAAM,mBAAmB,KAAK,oBAAoB,EACpE,IAAI,CAAC,UAAU,MAAM,QAAQ;AAChC,UAAI,SAAS,OAAQ,OAAM,KAAK,kBAAkB,QAAQ;AAAA,IAC5D;AAEA,SAAK,YAAY,OAAO;AAAA,EAC1B;AAAA,EAEA,MAAc,4BAA4B;AACxC,SAAK,yBAAyB;AAC9B,SAAK,oBAAoB;AAEzB,UAAM,SAA2B,EAAE,YAAY,KAAK,WAAW;AAC/D,SAAK,YAAY,IAAI,kBAAkB,MAAM;AAC7C,SAAK,aAAa,IAAI,kBAAkB,MAAM;AAK9C,SAAK,mBAAmB,KAAK,UAAU,eAAe,SAAS;AAAA,MAC7D,WAAW;AAAA,IACb,CAAC;AACD,SAAK,oBAAoB,KAAK,UAAU,eAAe,SAAS;AAAA,MAC9D,WAAW;AAAA,IACb,CAAC;AACD,SAAK,oBAAoB,KAAK,UAAU,eAAe,SAAS;AAAA,MAC9D,WAAW;AAAA,IACb,CAAC;AAED,SAAK,cAAc,KAAK,iBAAiB;AACzC,SAAK,cAAc,KAAK,kBAAkB;AAC1C,SAAK,eAAe,KAAK,kBAAkB;AAE3C,SAAK,UAAU,iBAAiB,CAAC,UAAU;AACzC,UAAI,MAAM,UAAW,MAAK,cAAc,aAAa,MAAM,SAAS;AAAA,IACtE;AAEA,SAAK,WAAW,iBAAiB,CAAC,UAAU;AAC1C,UAAI,MAAM,UAAW,MAAK,cAAc,cAAc,MAAM,SAAS;AAAA,IACvE;AAEA,SAAK,UAAU,0BAA0B,MAAM;AAC7C,YAAM,YAAY,KAAK;AACvB,UAAI,CAAC,UAAW;AAEhB,YAAM,QAAQ,UAAU;AAExB,cAAQ,MAAM,oCAAoC;AAAA,QAChD,iBAAiB,UAAU;AAAA,QAC3B,oBAAoB,UAAU;AAAA,QAC9B,mBAAmB,UAAU;AAAA,QAC7B,gBAAgB,UAAU;AAAA,MAC5B,CAAC;AAED,UAAI,UAAU,UAAU;AACtB,aAAK,cAAc,kBAAkB;AAAA,MACvC;AAAA,IACF;AAEA,SAAK,WAAW,0BAA0B,MAAM;AAC9C,YAAM,aAAa,KAAK;AACxB,UAAI,CAAC,WAAY;AAEjB,YAAM,QAAQ,WAAW;AAEzB,cAAQ,MAAM,qCAAqC;AAAA,QACjD,iBAAiB,WAAW;AAAA,QAC5B,oBAAoB,WAAW;AAAA,QAC/B,mBAAmB,WAAW;AAAA,QAC9B,gBAAgB,WAAW;AAAA,MAC7B,CAAC;AAED,UAAI,UAAU,UAAU;AACtB,aAAK,cAAc,mBAAmB;AAAA,MACxC;AAAA,IACF;AACA,SAAK,UAAU,6BAA6B,MAAM;AAChD,YAAM,YAAY,KAAK;AACvB,UAAI,CAAC,UAAW;AAEhB,cAAQ,MAAM,6BAA6B;AAAA,QACzC,oBAAoB,UAAU;AAAA,QAC9B,iBAAiB,UAAU;AAAA,MAC7B,CAAC;AAAA,IACH;AAEA,SAAK,WAAW,6BAA6B,MAAM;AACjD,YAAM,aAAa,KAAK;AACxB,UAAI,CAAC,WAAY;AAEjB,cAAQ,MAAM,8BAA8B;AAAA,QAC1C,oBAAoB,WAAW;AAAA,QAC/B,iBAAiB,WAAW;AAAA,MAC9B,CAAC;AAAA,IACH;AAEA,SAAK,WAAW,UAAU,CAAC,UAAU;AACnC,WAAK,KAAK,kBAAkB,KAAK;AAAA,IACnC;AAEA,QAAI,CAAC,KAAK,sBAAsB;AAC9B,WAAK,uBAAuB,YAAY,MAAM;AAC5C,aAAK,KAAK,wBAAwB;AAAA,MACpC,GAAG,GAAI;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,kBAAkB,OAAsB;AACpD,UAAM,SAAS,MAAM,UAAU,CAAC,KAAK;AACrC,UAAM,WAAW,KAAK,2BAA2B,MAAM,OAAO,MAAM;AAEpE,QAAI,CAAC,UAAU,gBAAgB;AAC7B,WAAK;AAAA,QACH,IAAI;AAAA,UACF,UAAU,MAAM,MAAM,IAAI,UAAU,MAAM,MAAM,EAAE;AAAA,QACpD;AAAA,MACF;AACA;AAAA,IACF;AAEA,UAAM,gBAAgB,SAAS;AAC/B,UAAM,SAAS;AAAA,MACb,SAAS,UAAU,KAAK,cAAc,IAAI,SAAS,QAAQ,KAAK;AAAA,IAClE,EACG,KAAK,EACL,YAAY;AAIf,QAAI,WAAW,YAAY,WAAW,gBAAgB;AACpD,UAAI,eAAe,KAAK,oBAAoB,IAAI,aAAa;AAE7D,UAAI,CAAC,cAAc;AACjB,uBAAe,IAAI,YAAY;AAC/B,aAAK,oBAAoB,IAAI,eAAe,YAAY;AAAA,MAC1D;AAEA,iBAAW,YAAY,aAAa,eAAe,GAAG;AACpD,YAAI,SAAS,OAAO,MAAM,MAAM,IAAI;AAClC,uBAAa,YAAY,QAAQ;AACjC,mBAAS,KAAK;AAAA,QAChB;AAAA,MACF;AAEA,UACE,CAAC,aAAa,UAAU,EAAE,KAAK,CAAC,UAAU,MAAM,OAAO,MAAM,MAAM,EAAE,GACrE;AACA,qBAAa,SAAS,MAAM,KAAK;AAAA,MACnC;AAEA,YAAM,MAAM,UAAU,MAAM;AAC1B,YAAI;AACF,wBAAc,YAAY,MAAM,KAAK;AAAA,QACvC,QAAQ;AAAA,QAAC;AAET,YAAI,cAAc,UAAU,EAAE,WAAW,GAAG;AAC1C,eAAK,oBAAoB,OAAO,aAAa;AAC7C,eAAK,qBAAqB,eAAe,SAAS,QAAQ;AAAA,QAC5D;AAAA,MACF;AAEA,WAAK,qBAAqB,eAAe,QAAQ;AACjD,WAAK,cAAc,MAAM,OAAO,cAAc;AAAA,QAC5C,GAAG;AAAA,QACH,QAAQ;AAAA,MACV,CAAC;AACD;AAAA,IACF;AAGA,QAAI,MAAM,MAAM,SAAS,WAAW,WAAW,UAAU;AACvD,WAAK;AAAA,QACH,IAAI;AAAA,UACF,4DAA4D,SAAS,QAAQ;AAAA,QAC/E;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,eAAe,KAAK,cAAc,IAAI,aAAa;AACvD,QAAI,CAAC,cAAc;AACjB,qBAAe,IAAI,YAAY;AAC/B,WAAK,cAAc,IAAI,eAAe,YAAY;AAAA,IACpD;AAEA,eAAW,YAAY,aAAa,UAAU,GAAG;AAC/C,UACE,SAAS,SAAS,MAAM,MAAM,QAC9B,SAAS,OAAO,MAAM,MAAM,IAC5B;AACA,qBAAa,YAAY,QAAQ;AACjC,iBAAS,KAAK;AAAA,MAChB;AAAA,IACF;AAEA,QACE,CAAC,aAAa,UAAU,EAAE,KAAK,CAAC,UAAU,MAAM,OAAO,MAAM,MAAM,EAAE,GACrE;AACA,mBAAa,SAAS,MAAM,KAAK;AAAA,IACnC;AAEA,UAAM,MAAM,UAAU,MAAM;AAC1B,UAAI;AACF,sBAAc,YAAY,MAAM,KAAK;AAAA,MACvC,QAAQ;AAAA,MAAC;AAAA,IACX;AAEA,SAAK,cAAc,MAAM,OAAO,cAAc;AAAA,MAC5C,GAAG;AAAA,MACH,QAAQ,MAAM,MAAM,SAAS,UAAU,UAAU;AAAA,IACnD,CAAC;AAAA,EACH;AAAA,EAEQ,uBAAuB,gBAAgC;AAC7D,WAAO,gBAAgB,WAAW,QAAQ,IACtC,eAAe,MAAM,SAAS,MAAM,IACpC;AAAA,EACN;AAAA,EAEQ,2BACN,OACA,QACkB;AAClB,UAAM,aAAa;AAAA,MACjB,KAAK,uBAAuB,MAAM,EAAE;AAAA,MACpC,MAAM;AAAA,MACN,QAAQ,KAAK,KAAK,uBAAuB,OAAO,EAAE,IAAI;AAAA,MACtD,QAAQ,MAAM;AAAA,IAChB,EAAE,OAAO,OAAO;AAEhB,eAAW,MAAM,YAAY;AAC3B,YAAM,WAAW,KAAK,cAAc,IAAI,EAAE;AAC1C,UAAI,SAAU,QAAO;AAAA,IACvB;AAKA,WAAO;AAAA,EACT;AAAA,EAEQ,cAAc,MAAgB,WAA4B;AAChE,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,QACP;AAAA,QACA,WAAW,UAAU;AAAA,QACrB,SAAS,UAAU;AAAA,QACnB,iBAAiB,UAAU;AAAA,QAC3B,mBAAmB,UAAU;AAAA,MAC/B;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,UAAU,SAAc;AACpC,UAAM,OACJ,QAAQ,SAAS,cAAc,cAAc;AAC/C,UAAM,KAAK,SAAS,cAAc,KAAK,YAAY,KAAK;AAExD,UAAM,YAAiC;AAAA,MACrC,WAAW,QAAQ;AAAA,MACnB,QAAQ,QAAQ,WAAW,QAAQ,UAAU;AAAA,MAC7C,eAAe,QAAQ,mBAAmB,QAAQ,iBAAiB;AAAA,MACnE,kBACE,QAAQ,qBAAqB,QAAQ,oBAAoB;AAAA,IAC7D;AAEA,QAAI,CAAC,MAAM,CAAC,GAAG,mBAAmB;AAChC,WAAK,WAAW,IAAI,EAAE,KAAK,SAAS;AACpC;AAAA,IACF;AAEA,QAAI;AACF,YAAM,GAAG,gBAAgB,SAAS;AAAA,IACpC,SAAS,OAAO;AACd,WAAK;AAAA,QACH,IAAI,MAAM,iBAAiB,IAAI,mBAAmB,OAAO,KAAK,CAAC,EAAE;AAAA,MACnE;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,gBAAgB,MAAgB;AAC5C,UAAM,KAAK,SAAS,cAAc,KAAK,YAAY,KAAK;AACxD,QAAI,CAAC,MAAM,CAAC,GAAG,kBAAmB;AAElC,UAAM,QAAQ,KAAK,WAAW,IAAI;AAClC,WAAO,MAAM,QAAQ;AACnB,YAAM,YAAY,MAAM,MAAM;AAC9B,UAAI;AACF,cAAM,GAAG,gBAAgB,SAAS;AAAA,MACpC,SAAS,OAAO;AACd,aAAK;AAAA,UACH,IAAI;AAAA,YACF,wBAAwB,IAAI,mBAAmB,OAAO,KAAK,CAAC;AAAA,UAC9D;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,oBAAoB;AAChC,QAAI,CAAC,KAAK,WAAY;AAEtB,WAAO,KAAK,WAAW,QAAQ;AAC7B,UAAI,KAAK,sBAAuB;AAChC,WAAK,wBAAwB;AAC7B,YAAM,QAAQ,KAAK,WAAW,MAAM;AAEpC,UAAI;AACF,cAAM,KAAK,WAAW,qBAAqB;AAAA,UACzC,MAAM;AAAA,UACN,KAAK,MAAM;AAAA,QACb,CAAC;AACD,cAAM,KAAK,gBAAgB,YAAY;AAEvC,cAAM,SAAS,MAAM,KAAK,WAAW,aAAa;AAClD,cAAM,KAAK,WAAW,oBAAoB,MAAM;AAEhD,aAAK,KAAK;AAAA,UACR,MAAM;AAAA,UACN,SAAS;AAAA,YACP,UAAU,MAAM;AAAA,YAChB,KAAK,OAAO;AAAA,UACd;AAAA,QACF,CAAC;AAKD,cAAM,SAAS,KAAK,oBAAoB,MAAM;AAC9C,gBAAQ,QAAQ;AAAA,MAClB,SAAS,OAAO;AACd,cAAM,SAAS,KAAK,oBAAoB,MAAM;AAC9C,YAAI,QAAQ;AACV,iBAAO,SAAS,QAAQ,CAAC,OAAO,KAAK,iBAAiB,OAAO,EAAE,CAAC;AAChE,iBAAO,OAAO,KAAK;AAAA,QACrB;AACA,aAAK;AAAA,UACH,IAAI,MAAM,uCAAuC,OAAO,KAAK,CAAC,EAAE;AAAA,QAClE;AAAA,MACF,UAAE;AACA,aAAK,wBAAwB;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,UAAU,SAAiB;AACvC,QAAI,CAAC,WAAW,KAAK,iBAAiB,IAAI,OAAO,EAAG;AACpD,SAAK,iBAAiB,IAAI,OAAO;AACjC,SAAK,kBAAkB,KAAK,OAAO;AACnC,QAAI,CAAC,KAAK,oBAAqB,OAAM,KAAK,yBAAyB;AAAA,EACrE;AAAA,EAEA,MAAc,kBAAkB,UAAoB;AAClD,UAAM,YAAY,CAAC,GAAG,IAAI,IAAI,SAAS,OAAO,OAAO,CAAC,CAAC,EAAE;AAAA,MACvD,CAAC,OAAO,CAAC,KAAK,iBAAiB,IAAI,EAAE;AAAA,IACvC;AACA,QAAI,CAAC,UAAU,UAAU,CAAC,KAAK,aAAa,EAAG;AAE/C,cAAU,QAAQ,CAAC,OAAO,KAAK,iBAAiB,IAAI,EAAE,CAAC;AACvD,WAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC5C,YAAM,OAAO,KAAK,KAAK;AAAA,QACrB,MAAM;AAAA,QACN,SAAS,EAAE,WAAW,UAAU;AAAA,MAClC,CAAC;AAED,UAAI,CAAC,MAAM;AACT,kBAAU,QAAQ,CAAC,OAAO,KAAK,iBAAiB,OAAO,EAAE,CAAC;AAC1D,eAAO,IAAI,MAAM,8BAA8B,CAAC;AAChD;AAAA,MACF;AAEA,WAAK,oBAAoB,KAAK;AAAA,QAC5B,UAAU;AAAA,QACV;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,2BAA2B;AACvC,SAAK,sBAAsB;AAC3B,QAAI;AACF,aAAO,KAAK,kBAAkB,QAAQ;AACpC,cAAM,UAAU,KAAK,kBAAkB,MAAM;AAC7C,YAAI,CAAC,KAAK,aAAa,GAAG;AACxB,eAAK,iBAAiB,OAAO,OAAO;AACpC;AAAA,QACF;AAEA,cAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,gBAAM,OAAO,KAAK,KAAK;AAAA,YACrB,MAAM;AAAA,YACN,SAAS,EAAE,WAAW,CAAC,OAAO,EAAE;AAAA,UAClC,CAAC;AAED,cAAI,CAAC,MAAM;AACT,iBAAK,iBAAiB,OAAO,OAAO;AACpC,mBAAO,IAAI,MAAM,8BAA8B,CAAC;AAChD;AAAA,UACF;AAEA,eAAK,oBAAoB,KAAK;AAAA,YAC5B,UAAU,CAAC,OAAO;AAAA,YAClB;AAAA,YACA;AAAA,UACF,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAAA,IACF,UAAE;AACA,WAAK,sBAAsB;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ,EAAE,QAAQ,MAAM,QAAQ,KAAK,IAAI,CAAC,GAAG;AACjD,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,6CAA6C;AAE/D,QAAI,CAAC,KAAK,aAAa;AACrB,WAAK,cAAc,MAAM,UAAU,aAAa,aAAa;AAAA,QAC3D;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,KAAK,sBAAsB,OAAO,KAAK;AAC7C,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,sBAAsB,QAAQ,MAAM,QAAQ,MAAM;AAC9D,QAAI,CAAC,KAAK,aAAa,CAAC,KAAK,YAAa;AAE1C,QACE,CAAC,KAAK,oBACN,CAAC,KAAK,qBACN,CAAC,KAAK,mBACN;AACA,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAEA,UAAM,aAAa,KAAK,YACrB,eAAe,EACf,KAAK,CAAC,UAAU,MAAM,eAAe,MAAM;AAC9C,UAAM,cAAc,KAAK,YACtB,eAAe,EACf,KAAK,CAAC,UAAU,MAAM,eAAe,MAAM;AAC9C,UAAM,cAAc,KAAK,cACrB,eAAe,EAChB,KAAK,CAAC,UAAU,MAAM,eAAe,MAAM;AAE9C,UAAM,KAAK,aAAa;AAAA,MACtB,SAAS,aAAa,aAAa;AAAA,IACrC;AACA,SAAK,iBAAiB,YACpB,SAAS,aAAa,aAAa;AAErC,UAAM,KAAK,aAAa;AAAA,MACtB,SAAS,cAAc,cAAc;AAAA,IACvC;AACA,SAAK,kBAAkB,YACrB,SAAS,cAAc,aAAa;AAEtC,UAAM,KAAK,cAAc,aAAa,eAAe,IAAI;AACzD,SAAK,kBAAkB,YAAY,cAAc,aAAa;AAE9D,QAAI,CAAC,cAAc,CAAC,eAAe,CAAC,YAAa;AAEjD,UAAM,QAAQ,MAAM,KAAK,UAAU,YAAY;AAC/C,UAAM,KAAK,UAAU,oBAAoB,KAAK;AAE9C,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,QACP,UAAU,EAAE,KAAK;AAAA,QACjB,KAAK,MAAM;AAAA,MACb;AAAA,IACF,CAAC;AAED,QAAI,aAAa;AACf,WAAK,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAAA,IAC1C;AAAA,EACF;AAAA,EAEA,MAAM,cAAc;AAClB,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,IAAI,MAAM,6CAA6C;AAAA,IAC/D;AAEA,QAAI,CAAC,KAAK,qBAAqB,CAAC,KAAK,cAAc;AACjD,YAAM,IAAI,MAAM,uCAAuC;AAAA,IACzD;AAEA,UAAM,WAAW,KAAK;AACtB,UAAM,gBAAgB,KAAK,aAAa;AAGxC,QAAI,YAAa,iBAAiB,cAAc,eAAe,QAAS;AACtE,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,KAAK,aAAa,aAAa,IAAI;AAAA,IAC3C,QAAQ;AAAA,IAAC;AAET,SAAK,kBAAkB,YAAY;AAEnC,UAAM,eAAe,MAAM,UAAU,aAAa,gBAAgB;AAAA,MAChE,OAAO;AAAA,MACP,OAAO;AAAA,IACT,CAAC;AAED,UAAM,cAAc,aAAa,eAAe,EAAE,CAAC;AAEnD,QAAI,CAAC,aAAa;AAChB,mBAAa,UAAU,EAAE,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AACxD,YAAM,IAAI,MAAM,sCAAsC;AAAA,IACxD;AAEA,UAAM,aAAa,EAAE,KAAK;AAE1B,SAAK,eAAe;AAEpB,QAAI;AACF,YAAM,KAAK,aAAa,aAAa,WAAW;AAEhD,WAAK,kBAAkB,YAAY;AAEnC,WAAK,KAAK;AAAA,QACR,MAAM;AAAA,MACR,CAAC;AAED,YAAM,QAAQ,MAAM,KAAK,UAAU,YAAY;AAE/C,YAAM,KAAK,UAAU,oBAAoB,KAAK;AAE9C,YAAM,mBAAmB,KAAK,UAAU;AAExC,UAAI,CAAC,kBAAkB,KAAK;AAC1B,cAAM,IAAI,MAAM,oDAAoD;AAAA,MACtE;AAEA,WAAK,KAAK;AAAA,QACR,MAAM;AAAA,QACN,SAAS;AAAA,UACP,UAAU,EAAE,KAAK;AAAA,UACjB,KAAK,iBAAiB;AAAA,QACxB;AAAA,MACF,CAAC;AAED,kBAAY,UAAU,MAAM;AAC1B,YAAI,eAAe,KAAK,uBAAuB;AAC7C;AAAA,QACF;AAEA,aAAK,KAAK,gBAAgB;AAAA,MAC5B;AAEA,aAAO,KAAK;AAAA,IACd,SAAS,OAAO;AACd,UAAI;AACF,cAAM,KAAK,aAAa,aAAa,IAAI;AAAA,MAC3C,QAAQ;AAAA,MAAC;AAET,WAAK,kBAAkB,YAAY;AAEnC,kBAAY,UAAU;AAEtB,mBAAa,UAAU,EAAE,QAAQ,CAAC,UAAU;AAC1C,YAAI;AACF,gBAAM,KAAK;AAAA,QACb,QAAQ;AAAA,QAAC;AAAA,MACX,CAAC;AAED,WAAK,eAAe;AAEpB,UAAI;AACF,aAAK,KAAK;AAAA,UACR,MAAM;AAAA,QACR,CAAC;AAAA,MACH,QAAQ;AAAA,MAAC;AAET,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,kBAAkB;AACtB,UAAM,SAAS,KAAK;AACpB,UAAM,cAAc,KAAK,cAAc,SAAS;AAEhD,QAAI,CAAC,UAAU,CAAC,aAAa;AAC3B;AAAA,IACF;AAEA,MAAE,KAAK;AAEP,QAAI,aAAa;AACf,kBAAY,UAAU;AAAA,IACxB;AAEA,QAAI;AACF,YAAM,KAAK,cAAc,aAAa,IAAI;AAAA,IAC5C,SAAS,OAAO;AACd,WAAK,QAAQ,KAAK;AAAA,IACpB;AAEA,QAAI,KAAK,mBAAmB;AAC1B,WAAK,kBAAkB,YAAY;AAAA,IACrC;AAEA,QAAI;AACF,UAAI,KAAK,WAAW;AAClB,cAAM,QAAQ,MAAM,KAAK,UAAU,YAAY;AAE/C,cAAM,KAAK,UAAU,oBAAoB,KAAK;AAE9C,cAAM,mBAAmB,KAAK,UAAU;AAExC,YAAI,kBAAkB,KAAK;AACzB,eAAK,KAAK;AAAA,YACR,MAAM;AAAA,YACN,SAAS;AAAA,cACP,UAAU,EAAE,KAAK;AAAA,cACjB,KAAK,iBAAiB;AAAA,YACxB;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,WAAK,QAAQ,KAAK;AAAA,IACpB;AAEA,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,IACR,CAAC;AAED,YAAQ,UAAU,EAAE,QAAQ,CAAC,UAAU;AACrC,UAAI;AACF,cAAM,KAAK;AAAA,MACb,QAAQ;AAAA,MAAC;AAAA,IACX,CAAC;AAED,SAAK,eAAe;AAEpB,QAAI,KAAK,sBAAsB;AAC7B,WAAK,qBAAqB,KAAK,oBAAoB;AAAA,IACrD;AAAA,EACF;AAAA,EAEA,UAAU,OAAgB;AACxB,SAAK,oBAAoB;AACzB,SAAK,aAAa,eAAe,EAAE,QAAQ,CAAC,UAAU;AACpD,YAAM,UAAU,CAAC;AAAA,IACnB,CAAC;AAED,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,SAAS,EAAE,aAAa,OAAO,aAAa,KAAK,kBAAkB;AAAA,IACrE,CAAC;AAED,UAAM,UAAU,KAAK,cAAc,IAAI,OAAO;AAC9C,QAAI,SAAS;AACX,WAAK,KAAK;AAAA,QACR,MAAM;AAAA,QACN,SAAS;AAAA,UACP,UAAU;AAAA,UACV;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,UAAU,OAAgB;AACxB,SAAK,oBAAoB;AACzB,SAAK,aAAa,eAAe,EAAE,QAAQ,CAAC,UAAU;AACpD,YAAM,UAAU,CAAC;AAAA,IACnB,CAAC;AAED,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,SAAS,EAAE,aAAa,KAAK,mBAAmB,aAAa,MAAM;AAAA,IACrE,CAAC;AAED,UAAM,UAAU,KAAK,cAAc,IAAI,QAAQ;AAC/C,QAAI,SAAS;AACX,WAAK,KAAK;AAAA,QACR,MAAM;AAAA,QACN,SAAS;AAAA,UACP,UAAU;AAAA,UACV;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,gBAAgB,OAIb;AACD,WAAO,KAAK,KAAK;AAAA,MACf,MAAM;AAAA,MACN,SAAS;AAAA,QACP,SAAS,MAAM;AAAA,QACf,UAAU,MAAM,YAAY;AAAA,QAC5B,QAAQ,MAAM,UAAU;AAAA,MAC1B;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,iBAAiB;AACrB,QAAI,CAAC,KAAK,KAAK,EAAE,MAAM,kBAAkB,CAAC,GAAG;AAC3C,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB;AACpB,QAAI,CAAC,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAC,GAAG;AAC1C,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,MAAM,qBAAqB;AACzB,QAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,OAAO;AAC7B,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AAEA,WAAO,KAAK;AAAA,MACV,GAAG,KAAK,OAAO,UAAU,mBAAmB,KAAK,IAAI,CAAC;AAAA,MACtD;AAAA,QACE,SAAS;AAAA,UACP,eAAe,UAAU,KAAK,KAAK;AAAA,QACrC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,mBAAmB,WAAmB;AAC1C,QAAI,CAAC,UAAW,OAAM,IAAI,MAAM,uBAAuB;AACvD,QACE,CAAC,KAAK,KAAK,EAAE,MAAM,gBAAgB,SAAS,EAAE,YAAY,UAAU,EAAE,CAAC,GACvE;AACA,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,MAAM,kBAAkB,WAAmB,QAAiB;AAC1D,QAAI,CAAC,UAAW,OAAM,IAAI,MAAM,uBAAuB;AACvD,QACE,CAAC,KAAK,KAAK;AAAA,MACT,MAAM;AAAA,MACN,SAAS,EAAE,YAAY,WAAW,OAAO;AAAA,IAC3C,CAAC,GACD;AACA,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAAA,EACF;AAAA,EAEQ,eAAe;AACrB,WAAO,KAAK,IAAI,eAAe,UAAU;AAAA,EAC3C;AAAA,EAEQ,KAAK,SAAc;AACzB,QAAI,CAAC,KAAK,aAAa,EAAG,QAAO;AACjC,SAAK,GAAI;AAAA,MACP,KAAK,UAAU;AAAA,QACb,YAAY,KAAK,cAAc;AAAA,QAC/B,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA,EAEA,aAAa,UAAwB;AACnC,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,QACP,OAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,wBAAwB,eAAuB;AACrD,UAAM,SAAS,KAAK,cAAc,IAAI,aAAa;AACnD,QAAI,QAAQ;AACV,aAAO,UAAU,EAAE,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AAClD,WAAK,cAAc,OAAO,aAAa;AAAA,IACzC;AAEA,UAAM,eAAe,KAAK,oBAAoB,IAAI,aAAa;AAC/D,QAAI,cAAc;AAChB,mBAAa,UAAU,EAAE,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AACxD,WAAK,oBAAoB,OAAO,aAAa;AAAA,IAC/C;AAEA,eAAW,CAAC,SAAS,QAAQ,KAAK,KAAK,eAAe;AACpD,UAAI,SAAS,mBAAmB,eAAe;AAC7C,aAAK,cAAc,OAAO,OAAO;AACjC,aAAK,iBAAiB,OAAO,OAAO;AACpC,aAAK,mBAAmB,OAAO,OAAO;AACtC,aAAK,cAAc,OAAO,OAAO;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ;AACZ,SAAK,cAAc;AACnB,SAAK,mBAAmB;AACxB,SAAK,SAAS,SAAS;AAEvB,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AAEA,UAAM,WAAW,KAAK;AACtB,UAAM,KAAK,KAAK;AAChB,SAAK,oBAAoB;AAEzB,QAAI,IAAI,eAAe,UAAU,MAAM;AACrC,YAAM,IAAI,QAAc,CAAC,YAAY;AACnC,YAAI,UAAU;AACd,cAAM,SAAS,MAAM;AACnB,cAAI,QAAS;AACb,oBAAU;AACV,kBAAQ;AAAA,QACV;AAIA,cAAM,UAAU,WAAW,QAAQ,IAAI;AAEvC,cAAM,QAAQ,MAAM;AAClB,cAAI,KAAK,qBAAqB,KAAK,OAAO,IAAI;AAC5C,yBAAa,OAAO;AACpB,mBAAO;AACP;AAAA,UACF;AACA,cAAI,GAAG,eAAe,UAAU,MAAM;AACpC,yBAAa,OAAO;AACpB,mBAAO;AACP;AAAA,UACF;AACA,qBAAW,OAAO,EAAE;AAAA,QACtB;AAEA,WAAG;AAAA,UACD;AAAA,UACA,MAAM;AACJ,yBAAa,OAAO;AACpB,mBAAO;AAAA,UACT;AAAA,UACA,EAAE,MAAM,KAAK;AAAA,QACf;AAEA,aAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC3B,cAAM;AAAA,MACR,CAAC;AAED,UAAI;AACF,WAAG,MAAM,KAAM,cAAc;AAAA,MAC/B,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,SAAK,iBAAiB,QAAQ;AAC9B,SAAK,WAAW;AAChB,SAAK,SAAS,cAAc;AAAA,EAC9B;AAAA,EAEQ,2BAA2B;AACjC,QAAI,KAAK,WAAW;AAClB,UAAI;AACF,aAAK,UAAU,MAAM;AAAA,MACvB,QAAQ;AAAA,MAER;AACA,WAAK,YAAY;AAAA,IACnB;AACA,QAAI,KAAK,YAAY;AACnB,UAAI;AACF,aAAK,WAAW,MAAM;AAAA,MACxB,QAAQ;AAAA,MAER;AACA,WAAK,aAAa;AAAA,IACpB;AACA,SAAK,cAAc;AACnB,SAAK,cAAc;AACnB,SAAK,eAAe;AACpB,SAAK,mBAAmB;AACxB,SAAK,oBAAoB;AACzB,SAAK,oBAAoB;AACzB,SAAK,aAAa,EAAE,WAAW,CAAC,GAAG,YAAY,CAAC,EAAE;AAClD,SAAK,aAAa,CAAC;AACnB,SAAK,wBAAwB;AAC7B,SAAK,oBAAoB,CAAC;AAC1B,SAAK,sBAAsB;AAC3B,SAAK,oBACF,OAAO,CAAC,EACR,QAAQ,CAAC,MAAM,EAAE,OAAO,IAAI,MAAM,0BAA0B,CAAC,CAAC;AACjE,SAAK,iBAAiB,MAAM;AAAA,EAC9B;AAAA,EAEQ,aAAa;AACnB,QAAI,KAAK,sBAAsB;AAC7B,oBAAc,KAAK,oBAAoB;AACvC,WAAK,uBAAuB;AAAA,IAC9B;AAEA,SAAK,yBAAyB;AAE9B,SAAK,aAAa,UAAU,EAAE,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AAC7D,SAAK,cAAc,UAAU,EAAE,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AAC9D,SAAK,cAAc;AACnB,SAAK,eAAe;AAEpB,eAAW,UAAU,KAAK,cAAc,OAAO,GAAG;AAChD,aAAO,UAAU,EAAE,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AAAA,IACpD;AACA,SAAK,cAAc,MAAM;AAEzB,eAAW,UAAU,KAAK,oBAAoB,OAAO,GAAG;AACtD,aAAO,UAAU,EAAE,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AAAA,IACpD;AACA,SAAK,oBAAoB,MAAM;AAE/B,SAAK,cAAc,MAAM;AACzB,SAAK,mBAAmB,MAAM;AAC9B,SAAK,cAAc,MAAM;AACzB,SAAK,cAAc,MAAM;AACzB,SAAK,aAAa,MAAM;AACxB,SAAK,uBAAuB;AAC5B,SAAK,cAAc;AACnB,SAAK,uBAAuB;AAC5B,SAAK,QAAQ;AACb,SAAK,OAAO;AAEZ,QAAI,KAAK,IAAI;AACX,UAAI;AACF,aAAK,GAAG,MAAM;AAAA,MAChB,QAAQ;AAAA,MAER;AACA,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAAA,EAEA,MAAc,0BAA0B;AACtC,QAAI,CAAC,KAAK,cAAc,KAAK,WAAW,oBAAoB;AAC1D;AACF,QAAI;AACF,YAAM,QAAQ,MAAM,KAAK,WAAW,SAAS;AAC7C,YAAM,QAAQ,CAAC,WAAgB;AAC7B,YACE,OAAO,SAAS,kBACf,OAAO,SAAS,WAAW,OAAO,cAAc,UACjD;AACA,kBAAQ,MAAM,0BAA0B;AAAA,YACtC,iBAAiB,OAAO;AAAA,YACxB,aAAa,OAAO;AAAA,YACpB,eAAe,OAAO;AAAA,YACtB,YAAY,OAAO;AAAA,YACnB,aAAa,OAAO;AAAA,UACtB,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,cAAc,QAAgB;AACpC,QAAI,KAAK,iBAAkB;AAE3B,QAAI,KAAK,6BAA6B;AACpC,cAAQ,MAAM,6CAA6C;AAAA,QACzD;AAAA,MACF,CAAC;AACD;AAAA,IACF;AAEA,SAAK,8BAA8B;AAEnC,YAAQ,KAAK,oDAAoD;AAAA,MAC/D;AAAA,MACA,gBAAgB,KAAK,WAAW;AAAA,MAChC,mBAAmB,KAAK,WAAW;AAAA,MACnC,iBAAiB,KAAK,YAAY;AAAA,MAClC,oBAAoB,KAAK,YAAY;AAAA,IACvC,CAAC;AAED,SAAK,SAAS,cAAc;AAE5B,SAAK,yBAAyB,WAAW,MAAM;AAC7C,WAAK,yBAAyB;AAE9B,UAAI,KAAK,kBAAkB;AACzB,aAAK,8BAA8B;AACnC;AAAA,MACF;AAEA,YAAM,KAAK,KAAK;AAEhB,UAAI,MAAM,GAAG,eAAe,UAAU,MAAM;AAC1C,YAAI;AACF,aAAG,MAAM,KAAM,iBAAiB;AAAA,QAClC,SAAS,OAAO;AACd,kBAAQ,KAAK,gDAAgD,KAAK;AAElE,eAAK,8BAA8B;AACnC,eAAK,kBAAkB;AAAA,QACzB;AAEA;AAAA,MACF;AAEA,WAAK,8BAA8B;AACnC,WAAK,kBAAkB;AAAA,IACzB,GAAG,GAAG;AAAA,EACR;AACF;;;ACn+DO,IAAM,eAAN,MAAmB;AAAA,EA+CxB,YACE,SACQ,SAAiB,CAAC,GAClB,UAAkB,WAAW,SAC7B,SAAiB,WAAW,QACpC;AAHQ;AACA;AACA;AAlDV,SAAQ,YAA8B;AAEtC,SAAQ,OAGJ;AAAA,MACF,IAAI;AAAA,MACJ,MAAM;AAAA,IACR;AACA,SAAQ,cAAkC;AAC1C,SAAQ,eAAmC;AAC3C,SAAQ,kBAAkB;AAC1B,SAAQ,kBAAkB;AAI1B,SAAQ,wBAAwB;AAEhC,SAAQ,gBAAgB,oBAAI,IAAyB;AACrD,SAAQ,sBAAsB,oBAAI,IAAyB;AAI3D,SAAQ,cAAoC;AAC5C,SAAQ,oBAA0C;AA4BhD,SAAK,QAAQ,IAAI,aAAa;AAC9B,SAAK,SAAS;AACd,SAAK,wBAAwB,IAAI,sBAAsB;AAAA,MACrD,yBAAyB,CAAC,mBAAmB;AAC3C,aAAK,MAAM,kBAAkB,cAAc;AAE3C,aAAK,OAAO,0BAA0B,cAAc;AAAA,MACtD;AAAA,IACF,CAAC;AACD,SAAK,OAAO,QAAQ;AAAA,EACtB;AAAA,EApCQ,UACN,MACA,SACA,KACA,cAAc,MACd;AACA,UAAM,MAAgB;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ,KAAK,KAAK;AAAA,MAClB,eAAe,KAAK;AAAA,MACpB;AAAA,IACF;AAEA,SAAK,OAAO,UAAU,GAAG;AAEzB,YAAQ,MAAM,sBAAsB,GAAG;AAAA,EACzC;AAAA;AAAA,EAsBA,MAAM,UAAU,OAAyB,MAAc;AACrD,SAAK,kBAAkB;AAEvB,QAAI;AACF,WAAK,cAAc,MAAM,UAAU,aAAa,aAAa;AAAA,QAC3D,OAAO;AAAA,UACL,OAAO,EAAE,OAAO,KAAK;AAAA,UACrB,QAAQ,EAAE,OAAO,IAAI;AAAA,QACvB;AAAA,QACA,OAAO;AAAA,UACL,kBAAkB;AAAA,UAClB,kBAAkB;AAAA,UAClB,iBAAiB;AAAA,QACnB;AAAA,MACF,CAAC;AAED,YAAM,kBAAkB,KAAK,YAAY,eAAe,EAAE,CAAC;AAE3D,UAAI,iBAAiB;AACnB,aAAK,sBAAsB,SAAS,KAAK,MAAM,eAAe;AAAA,MAChE;AAEA,YAAM,WAAW,KAAK,YACnB,eAAe,EACf,KAAK,CAAC,MAAM,EAAE,eAAe,MAAM;AAEtC,YAAM,WAAW,KAAK,YACnB,eAAe,EACf,KAAK,CAAC,MAAM,EAAE,eAAe,MAAM;AAEtC,UAAI,CAAC,YAAY,CAAC,UAAU;AAC1B,cAAM,IAAI,MAAM,yBAAyB,QAAQ,WAAW,QAAQ,EAAE;AAAA,MACxE;AAEA,YAAM,YAAY,KAAK;AAEvB,WAAK,iBAAiB;AAAA,IACxB,SAAS,KAAU;AACjB,WAAK,UAAU,yBAAyB,KAAK,SAAS,KAAK,KAAK;AAEhE,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEQ,iBAAiB,aAAa,OAAO,aAAa,OAAO;AAC/D,QAAI,CAAC,KAAK,YAAa;AAEvB,SAAK,MAAM,uBAAuB;AAAA,MAChC,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MAEX,OAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,aAAa,KAAK,YAAY,eAAe,EAAE,CAAC;AAAA,QAChD,YAAY,KAAK,YAAY,eAAe,EAAE,CAAC;AAAA,QAC/C,YACE,KAAK,YAAY,eAAe,EAAE,CAAC,GAAG,WAAW,CAAC;AAAA,QACpD,YACE,KAAK,YAAY,eAAe,EAAE,CAAC,GAAG,WAAW,CAAC;AAAA,QACpD,iBAAiB,KAAK;AAAA,QACtB,cAAc,KAAK;AAAA,QACnB,aAAa,KAAK,cAAc,eAAe,EAAE,CAAC;AAAA,MACpD;AAAA,IACF,CAAC;AAED,SAAK,MAAM,cAAc,KAAK;AAAA,EAChC;AAAA;AAAA,EAGA,MAAM,WAAW,OAKd;AACD,UAAM,SACJ,KAAK,aACL,IAAI,UAAU;AAAA,MACZ,SAAS,KAAK;AAAA,MACd,QAAQ,KAAK;AAAA,MACb,eAAe,KAAK;AAAA,IACtB,CAAC;AAEH,WAAO,OAAO,WAAW,KAAK;AAAA,EAChC;AAAA,EAEA,MAAM,QAAQ,UAAkB;AAC9B,UAAM,SACJ,KAAK,aACL,IAAI,UAAU;AAAA,MACZ,SAAS,KAAK;AAAA,MACd,QAAQ,KAAK;AAAA,MACb,eAAe,KAAK;AAAA,IACtB,CAAC;AAEH,WAAO,OAAO,QAAQ,QAAQ;AAAA,EAChC;AAAA,EAEA,MAAM,WAAW,UAAkB;AACjC,UAAM,SACJ,KAAK,aACL,IAAI,UAAU;AAAA,MACZ,SAAS,KAAK;AAAA,MACd,QAAQ,KAAK;AAAA,MACb,eAAe,KAAK;AAAA,IACtB,CAAC;AAEH,WAAO,OAAO,WAAW,QAAQ;AAAA,EACnC;AAAA;AAAA,EAGA,MAAM,YACJ,QACe;AACf,UAAM,EAAE,QAAQ,MAAM,aAAa,OAAO,aAAa,MAAM,IAAI;AAEjE,QAAI,CAAC,UAAU,CAAC,MAAM;AACpB,YAAM,IAAI,MAAM,8CAA8C;AAAA,IAChE;AAEA,QAAI,CAAC,KAAK,MAAM;AACd,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAKA,QACE,KAAK,aACL,KAAK,KAAK,OAAO,UACjB,KAAK,UAAU,mBAAmB,MAAM,aACxC;AACA,cAAQ,KAAK,mDAAmD;AAAA,QAC9D;AAAA,QACA,eAAe,KAAK;AAAA,MACtB,CAAC;AAED;AAAA,IACF;AAEA,QAAI,KAAK,aAAa;AACpB,cAAQ;AAAA,QACN;AAAA,QACA;AAAA,UACE;AAAA,UACA,eAAe,KAAK;AAAA,QACtB;AAAA,MACF;AAEA,aAAO,KAAK;AAAA,IACd;AAEA,QAAI,KAAK,aAAa,KAAK,KAAK,MAAM,KAAK,KAAK,OAAO,QAAQ;AAC7D,YAAM,IAAI;AAAA,QACR,6BAA6B,KAAK,KAAK,EAAE;AAAA,MAC3C;AAAA,IACF;AAEA,SAAK,wBAAwB;AAC7B,SAAK,kBAAkB;AACvB,SAAK,KAAK,KAAK;AACf,SAAK,KAAK,OAAO;AAEjB,QAAI,CAAC,KAAK,aAAa;AACrB,WAAK,cAAc,MAAM,UAAU,aAAa,aAAa;AAAA,QAC3D,OAAO;AAAA,QACP,OAAO;AAAA,MACT,CAAC;AAED,YAAM,kBAAkB,KAAK,YAAY,eAAe,EAAE,CAAC;AAE3D,UAAI,iBAAiB;AACnB,aAAK,sBAAsB,SAAS,KAAK,MAAM,eAAe;AAAA,MAChE;AAAA,IACF;AAEA,SAAK,YAAY,eAAe,EAAE,QAAQ,CAAC,UAAU;AACnD,YAAM,UAAU,CAAC;AAAA,IACnB,CAAC;AAED,SAAK,YAAY,eAAe,EAAE,QAAQ,CAAC,UAAU;AACnD,YAAM,UAAU,CAAC;AAAA,IACnB,CAAC;AAED,SAAK,iBAAiB,YAAY,UAAU;AAE5C,UAAM,UAAU,KAAK,QAAQ,QAAQ,IAAI;AAEzC,SAAK,cAAc;AAEnB,QAAI;AACF,YAAM;AAAA,IACR,UAAE;AACA,UAAI,KAAK,gBAAgB,SAAS;AAChC,aAAK,cAAc;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,QAAQ,QAAgB,MAA6B;AACjE,QAAI,KAAK,WAAW;AAClB,YAAM,QAAQ,KAAK,UAAU,mBAAmB;AAChD,UACE,KAAK,KAAK,OAAO,WAChB,UAAU,gBACT,UAAU,eACV,UAAU,iBACZ;AACA,gBAAQ;AAAA,UACN;AAAA,UACA;AAAA,YACE;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAEA;AAAA,MACF;AAEA,YAAM,IAAI;AAAA,QACR,uCAAuC,KAAK;AAAA,MAC9C;AAAA,IACF;AAEA,UAAM,SAAS,IAAI,UAAU;AAAA,MAC3B,SAAS,KAAK;AAAA,MACd,QAAQ,KAAK;AAAA,MACb,eAAe,KAAK;AAAA,MACpB,eAAe;AAAA;AAAA,MAGf,eAAe,CAAC,UAAU;AACxB,aAAK,eAAe,KAAK;AAAA,MAC3B;AAAA,MAEA,aAAa,CAAC,SAAS,YAAY;AACjC,gBAAQ,IAAI,SAAS,UAAU,YAAY,QAAQ,SAAS,OAAO;AAEnE,aAAK,MAAM,uBAAuB;AAAA,UAChC,IAAI,KAAK;AAAA,UACT,MAAM,KAAK;AAAA,QACb,CAAC;AAAA,MACH;AAAA,MAEA,gBAAgB,MAAM;AAMpB,gBAAQ,IAAI,sDAAsD;AAAA,MACpE;AAAA,MAEA,gBAAgB,CAAC,YAAY;AAC3B,gBAAQ,KAAK,+BAA+B,OAAO,EAAE;AAAA,MACvD;AAAA;AAAA,MAGA,cAAc,CAAC,YAAY;AACzB,cAAM,eAAe,SAAS,gBAAgB,CAAC;AAC/C,cAAM,QAAQ,aAAa;AAAA,UACzB,CAAC,MAAW,GAAG,mBAAmB,KAAK;AAAA,QACzC;AACA,YAAI,OAAO;AACT,gBAAM,QAAQ,KAAK,MAAM,kBAAkB;AAC3C,eAAK,MAAM,uBAAuB;AAAA,YAChC,IAAI,KAAK;AAAA,YACT,MAAM,KAAK;AAAA,YACX,OAAO;AAAA,cACL,YAAY,CAAC,QAAQ,MAAM,WAAW;AAAA,cACtC,YAAY,CAAC,QAAQ,MAAM,WAAW;AAAA,cACtC,iBAAiB,QAAQ,MAAM,cAAc;AAAA,cAC7C,cAAc,KAAK;AAAA,cACnB,aAAa,KAAK,cAAc,eAAe,EAAE,CAAC;AAAA,YACpD;AAAA,UACF,CAAC;AACD,cAAI,KAAK,aAAa;AACpB,iBAAK,YAAY,eAAe,EAAE,QAAQ,CAAC,UAAU;AACnD,oBAAM,UAAU,CAAC,QAAQ,MAAM,WAAW;AAAA,YAC5C,CAAC;AACD,iBAAK,YAAY,eAAe,EAAE,QAAQ,CAAC,UAAU;AACnD,oBAAM,UAAU,CAAC,QAAQ,MAAM,WAAW;AAAA,YAC5C,CAAC;AAAA,UACH;AACA,cAAI,MAAM,eAAgB,MAAK,MAAM,eAAe,KAAK,IAAI;AAAA,mBACpD,KAAK,MAAM,gBAAgB,KAAK;AACvC,iBAAK,MAAM,eAAe,IAAI;AAAA,QAClC;AACA,cAAM,YAAY,aAAa,KAAK,CAAC,MAAW,GAAG,cAAc;AACjE,YAAI,UAAW,MAAK,MAAM,eAAe,UAAU,cAAc;AAAA,iBACxD,CAAC,OAAO,eAAgB,MAAK,MAAM,eAAe,IAAI;AAC/D,mBAAW,WAAW,SAAS,gBAAgB,CAAC,GAAG;AACjD,eAAK,MAAM,eAAe,OAAO;AAAA,QACnC;AACA,aAAK,OAAO,eAAe,OAAO;AAAA,MACpC;AAAA,MAEA,eAAe,CAAC,SAAS;AAKvB,gBAAQ,IAAI,8BAA8B,IAAI;AAAA,MAChD;AAAA,MAEA,gBAAgB,CAAC,cAAc;AAC7B,gBAAQ,IAAI,uBAAuB,SAAS;AAC5C,aAAK,OAAO,iBAAiB,SAAS;AACtC,aAAK,OAAO;AAAA,UACV;AAAA,YACE,eAAe,KAAK;AAAA,YACpB,UAAU;AAAA,UACZ;AAAA,UAEA;AAAA,QACF;AAAA,MACF;AAAA,MAEA,gBAAgB,CAAC,WAAW,WAAW;AACrC,gBAAQ,KAAK,uBAAuB,WAAW,MAAM;AACrD,aAAK,OAAO,iBAAiB,SAAS;AACtC,aAAK,OAAO;AAAA,UACV;AAAA,YACE,eAAe,KAAK;AAAA,YACpB,UAAU;AAAA,UACZ;AAAA,UAEA;AAAA,QACF;AAEA,aAAK;AAAA,UACH;AAAA,UACA,UAAU;AAAA,UACV;AAAA,YACE;AAAA,YACA;AAAA,UACF;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,MAEA,eAAe,CAAC,YAAY;AAC1B,cAAM,MAAM;AAAA,UACV,IAAI,QAAQ;AAAA,UACZ,MAAM,QAAQ;AAAA,UACd,WAAW,QAAQ;AAAA,UACnB,aAAa,QAAQ;AAAA,UACrB,WAAW,OAAO,QAAQ,SAAS;AAAA,UACnC,UAAU,QAAQ,YAAY;AAAA,UAC9B,QAAQ,QAAQ,UAAU;AAAA,QAC5B;AACA,aAAK,MAAM,eAAe,GAAG;AAC7B,aAAK,OAAO,gBAAgB,GAAG;AAAA,MACjC;AAAA,MAEA,iBAAiB,CAAC,YAAY;AAC5B,cAAM,YAAY,SAAS,cAAc,SAAS;AAClD,cAAM,gBAAgB,SAAS,WAAW,SAAS;AACnD,cAAM,YACJ,SAAS,eAAe,QACxB,SAAS,gBACT,SAAS,QACT;AAEF,YAAI,CAAC,aAAa,CAAC,eAAe;AAChC;AAAA,QACF;AAEA,aAAK,OAAO,mBAAmB;AAAA,UAC7B;AAAA,UACA;AAAA,UACA,MAAM;AAAA,QACR,CAAC;AAAA,MACH;AAAA;AAAA,MAGA,qBAAqB,CAAC,gBAAgB;AACpC,cAAM,MAAM,YAAY;AAExB,YAAI,CAAC,OAAO,QAAQ,KAAK,MAAM;AAC7B;AAAA,QACF;AAEA,cAAM,QACJ,YAAY,eAAe,QAC3B,YAAY,gBACZ;AAEF,aAAK,MAAM,eAAe;AAAA,UACxB,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,iBAAiB;AAAA,UACjB,OAAO;AAAA,YACL,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,iBAAiB;AAAA,YACjB,QAAQ;AAAA,UACV;AAAA,QACF,CAAC;AAED,aAAK,OAAO,eAAe;AAAA,UACzB,IAAI;AAAA,UACJ,MAAM;AAAA,QACR,CAAC;AAAA,MACH;AAAA,MAEA,uBAAuB,CAAC,eAAe,aAAa;AAClD,YAAI,kBAAkB,KAAK,MAAM;AAC/B;AAAA,QACF;AAEA,cAAM,UAAU,KAAK,MAAM,eAAe,aAAa;AAEvD,YAAI,CAAC,SAAS;AACZ;AAAA,QACF;AAEA,cAAM,kBACJ,aAAa,iBACT,iBACA,aAAa,eAAe,aAAa,WACvC,cACA,aAAa,iBACX,iBACA,QAAQ;AAElB,aAAK,MAAM,uBAAuB,eAAe;AAAA,UAC/C,QAAQ,QAAQ,OAAO,UAAU;AAAA,QACnC,CAAC;AAED,cAAM,OAAO,IAAI,IAAI,KAAK,MAAM,YAAY;AAE5C,aAAK,IAAI,eAAe;AAAA,UACtB,GAAG;AAAA,UACH;AAAA,QACF,CAAC;AAED,aAAK,MAAM,eAAe;AAE1B,aAAK,MAAM,OAAO,eAAe,aAAa,EAAE;AAEhD,aAAK,MAAM,OAAO,cAAc;AAAA,MAClC;AAAA,MAEA,mBAAmB,CAAC,gBAAgB;AAClC,cAAM,MACJ,OAAO,gBAAgB,WACnB,cACA,YAAY;AAElB,YAAI,CAAC,KAAK;AACR;AAAA,QACF;AAEA,gBAAQ,IAAI,sCAAsC,GAAG;AAErD,aAAK,yBAAyB,GAAG;AACjC,aAAK,MAAM,kBAAkB,GAAG;AAChC,aAAK,OAAO,aAAa,GAAG;AAAA,MAC9B;AAAA;AAAA,MAGA,yBAAyB,CAAC,eAAe,YAAY,eAAe;AAClE,YAAI,kBAAkB,KAAK,KAAM;AACjC,cAAM,cAAc,KAAK,MAAM,eAAe,aAAa;AAC3D,YAAI,CAAC,YAAa;AAClB,aAAK,MAAM,uBAAuB,eAAe;AAAA,UAC/C,YAAY,CAAC;AAAA,UACb,YAAY,CAAC;AAAA,QACf,CAAC;AACD,aAAK,OAAO,qBAAqB,eAAe,SAAS,UAAU;AACnE,aAAK,OAAO,qBAAqB,eAAe,SAAS,UAAU;AAAA,MACrE;AAAA,MAEA,kBAAkB,CAAC,UAAU;AAC3B,gBAAQ,IAAI,yBAAyB,KAAK;AAAA,MAC5C;AAAA,MAEA,oBAAoB,CAAC,UAAU;AAC7B,gBAAQ,IAAI,2BAA2B,KAAK;AAC5C,cAAM,MAAM,MAAM;AAElB,YAAI,CAAC,KAAK;AACR;AAAA,QACF;AAEA,cAAM,UAAU,KAAK,MAAM,eAAe,GAAG;AAC7C,YAAI,MAAM,WAAW,UAAU;AAC7B,gBAAM,SAAS,KAAK,oBAAoB,IAAI,GAAG;AAE/C,kBAAQ,UAAU,EAAE,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;AAE3C,eAAK,oBAAoB,OAAO,GAAG;AAEnC,eAAK,MAAM,uBAAuB,KAAK;AAAA,YACrC,iBAAiB;AAAA,YACjB,cAAc;AAAA,YACd,aAAa;AAAA,UACf,CAAC;AAED,eAAK,OAAO,uBAAuB,GAAG;AAEtC;AAAA,QACF;AAEA,YAAI,CAAC,SAAS;AACZ;AAAA,QACF;AAEA,aAAK,MAAM,uBAAuB,KAAK;AAAA,UACrC,QAAQ,QAAQ,OAAO,UAAU;AAAA,UACjC,YACE,MAAM,SAAS,UACX,QACC,QAAQ,OAAO,cAAc;AAAA,UAEpC,YACE,MAAM,SAAS,UACX,QACC,QAAQ,OAAO,cAAc;AAAA,QACtC,CAAC;AAAA,MACH;AAAA,MAEA,qBAAqB,CAAC,UAAU;AAC9B,cAAM,MAAM,MAAM;AAElB,YAAI,CAAC,OAAO,QAAQ,KAAK,MAAM;AAC7B;AAAA,QACF;AAEA,cAAM,UAAU,KAAK,MAAM,eAAe,GAAG;AAE7C,YAAI,CAAC,SAAS;AACZ;AAAA,QACF;AAEA,YAAI,MAAM,WAAW,SAAS;AAC5B,eAAK,MAAM,uBAAuB,KAAK;AAAA,YACrC,QAAQ,QAAQ,OAAO,UAAU;AAAA,YACjC,YAAY,CAAC,MAAM;AAAA,UACrB,CAAC;AAED,eAAK,OAAO,qBAAqB,KAAK,SAAS,MAAM,KAAK;AAAA,QAC5D,WAAW,MAAM,WAAW,UAAU;AACpC,eAAK,MAAM,uBAAuB,KAAK;AAAA,YACrC,QAAQ,QAAQ,OAAO,UAAU;AAAA,YACjC,YAAY,CAAC,MAAM;AAAA,UACrB,CAAC;AAED,eAAK,OAAO,qBAAqB,KAAK,SAAS,MAAM,KAAK;AAAA,QAC5D;AAEA,aAAK,OAAO,sBAAsB,KAAY;AAAA,MAChD;AAAA;AAAA,MAGA,oBAAoB,CAAC,cAAc;AACjC,aAAK,OAAO,qBAAqB,SAAS;AAAA,MAC5C;AAAA,MAEA,oBAAoB,CAAC,cAAc;AACjC,aAAK,OAAO,qBAAqB,SAAS;AAAA,MAC5C;AAAA;AAAA,MAGA,eAAe,CAAC,OAAO,QAAQ,aAAa;AAC1C,aAAK,kBAAkB,OAAO,QAAQ,QAAQ;AAAA,MAChD;AAAA;AAAA,MAGA,sBAAsB,CAAC,eAAe,WAAW;AAC/C,gBAAQ,IAAI,8BAA8B,aAAa;AAEvD,YAAI,kBAAkB,KAAK,MAAM;AAC/B,cAAI,CAAC,KAAK,cAAc;AACtB,iBAAK,eAAe,KAAK,WAAW,gBAAgB,KAAK;AAAA,UAC3D;AAEA,eAAK,MAAM,eAAe,aAAa;AACvC,eAAK,MAAM,uBAAuB;AAAA,YAChC,OAAO;AAAA,cACL,iBAAiB;AAAA,cACjB,cAAc,KAAK;AAAA,cACnB,aAAa,KAAK,cAAc,eAAe,EAAE,CAAC;AAAA,YACpD;AAAA,UACF,CAAC;AACD;AAAA,QACF;AAEA,aAAK,MAAM,eAAe,aAAa;AAKvC,cAAM,uBACJ,KAAK,WAAW,sBAAsB,aAAa,KACnD,KAAK,oBAAoB,IAAI,aAAa,KAC1C;AAEF,YAAI,sBAAsB;AACxB,eAAK,oBAAoB,IAAI,eAAe,oBAAoB;AAChE,gBAAM,cAAc,qBAAqB,eAAe,EAAE,CAAC;AAC3D,eAAK,MAAM,uBAAuB,eAAe;AAAA,YAC/C,iBAAiB;AAAA,YACjB,cAAc;AAAA,YACd;AAAA,UACF,CAAC;AACD,eAAK,OAAO;AAAA,YACV;AAAA,YACA;AAAA,UACF;AACA;AAAA,QACF;AAEA,cAAM,UAAU,KAAK,MAAM,eAAe,aAAa;AACvD,YAAI,SAAS;AACX,eAAK,MAAM,uBAAuB,eAAe;AAAA,YAC/C,iBAAiB;AAAA,YACjB,cAAc,QAAQ,OAAO,gBAAgB;AAAA,YAC7C,aAAa,QAAQ,OAAO;AAAA,UAC9B,CAAC;AAAA,QACH;AAAA,MACF;AAAA,MAEA,sBAAsB,CAAC,kBAAkB;AACvC,YAAI,KAAK,MAAM,gBAAgB,eAAe;AAC5C,eAAK,MAAM,eAAe,IAAI;AAAA,QAChC;AAEA,YAAI,kBAAkB,KAAK,MAAM;AAC/B,eAAK,MAAM,uBAAuB;AAAA,YAChC,OAAO;AAAA,cACL,iBAAiB;AAAA,cACjB,cAAc;AAAA,cACd,aAAa;AAAA,YACf;AAAA,UACF,CAAC;AACD;AAAA,QACF;AAKA,aAAK,MAAM,uBAAuB,eAAe;AAAA,UAC/C,iBAAiB;AAAA,QACnB,CAAC;AAED,aAAK,OAAO,uBAAuB,aAAa;AAAA,MAClD;AAAA;AAAA,MAGA,SAAS,CAAC,UAAU;AAClB,gBAAQ,MAAM,gBAAgB,KAAK;AAEnC,YACE,OAAO,SAAS,oBAChB,OAAO,SAAS,iBAChB;AACA,eAAK,UAAU,qBAAqB,MAAM,SAAS,OAAO,KAAK;AAE/D;AAAA,QACF;AAEA,aAAK;AAAA,UACH;AAAA,UACA,OAAO,WAAW,OAAO,KAAK;AAAA,UAC9B;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAMD,SAAK,YAAY;AAEjB,WAAO,eAAe,KAAK,WAAW;AAEtC,UAAM,OAAO,SAAS,QAAQ;AAAA,MAC5B,aAAa;AAAA,MACb,eAAe,KAAK;AAAA,MACpB,YAAY,EAAE,KAAK,aAAa,eAAe,EAAE,CAAC,GAAG,WAAW;AAAA,MAChE,YAAY,EAAE,KAAK,aAAa,eAAe,EAAE,CAAC,GAAG,WAAW;AAAA,IAClE,CAAC;AAAA,EACH;AAAA;AAAA,EAGQ,eAAe,OAA2B;AAChD,SAAK,OAAO,2BAA2B,KAAK;AAE5C,QAAI,UAAU,gBAAgB;AAC5B,WAAK,MAAM,uBAAuB;AAAA,QAChC,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,MACb,CAAC;AAED;AAAA,IACF;AAMA,QAAI,UAAU,kBAAkB,CAAC,KAAK,uBAAuB;AAC3D,WAAK;AAAA,QACH;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGQ,kBACN,OACA,QACA,UACA;AACA,UAAM,gBAAgB,UAAU;AAEhC,QAAI,CAAC,iBAAiB,kBAAkB,KAAK,MAAM;AACjD;AAAA,IACF;AAEA,UAAM,SAAS,SAAS;AAIxB,QAAI,WAAW,UAAU;AACvB,UAAI,eAAe,KAAK,oBAAoB,IAAI,aAAa;AAE7D,UAAI,CAAC,cAAc;AACjB,uBAAe,IAAI,YAAY;AAC/B,aAAK,oBAAoB,IAAI,eAAe,YAAY;AAAA,MAC1D;AAEA,iBAAW,OAAO,aAAa,eAAe,GAAG;AAC/C,YAAI,IAAI,OAAO,MAAM,IAAI;AACvB,uBAAa,YAAY,GAAG;AAC5B,cAAI,KAAK;AAAA,QACX;AAAA,MACF;AAEA,UAAI,CAAC,aAAa,UAAU,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,EAAE,GAAG;AAC5D,qBAAa,SAAS,KAAK;AAAA,MAC7B;AAEA,WAAK,MAAM,uBAAuB,eAAe;AAAA,QAC/C;AAAA,QACA,aAAa;AAAA,QACb,iBAAiB;AAAA,MACnB,CAAC;AAED,WAAK,OAAO,uBAAuB,eAAe,YAAY;AAE9D;AAAA,IACF;AAEA,QAAI,eAAe,KAAK,cAAc,IAAI,aAAa;AAEvD,QAAI,CAAC,cAAc;AACjB,qBAAe,IAAI,YAAY;AAE/B,WAAK,cAAc,IAAI,eAAe,YAAY;AAAA,IACpD;AAEA,eAAW,OAAO,aAAa,UAAU,GAAG;AAC1C,UAAI,IAAI,SAAS,MAAM,QAAQ,IAAI,OAAO,MAAM,IAAI;AAClD,qBAAa,YAAY,GAAG;AAC5B,YAAI,KAAK;AAAA,MACX;AAAA,IACF;AAEA,QAAI,CAAC,aAAa,UAAU,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,EAAE,GAAG;AAC5D,mBAAa,SAAS,KAAK;AAAA,IAC7B;AAEA,UAAM,UAAU,KAAK,MAAM,eAAe,aAAa;AAEvD,SAAK,MAAM,uBAAuB,eAAe;AAAA,MAC/C,QAAQ;AAAA,MACR,aAAa,MAAM,SAAS,UAAU,QAAQ,SAAS,OAAO;AAAA,MAC9D,YAAY,MAAM,SAAS,UAAU,QAAQ,SAAS,OAAO;AAAA,IAC/D,CAAC;AAED,QAAI,MAAM,SAAS,SAAS;AAC1B,WAAK,sBAAsB,SAAS,eAAe,KAAK;AAAA,IAC1D;AAEA,SAAK,OAAO,UAAU,cAAc,aAAa;AAEjD,UAAM,UAAU,MAAM;AACpB,UAAI,MAAM,SAAS,SAAS;AAC1B,aAAK,MAAM,uBAAuB,eAAe;AAAA,UAC/C,YAAY;AAAA,UACZ,QAAQ;AAAA,QACV,CAAC;AAED;AAAA,MACF;AAEA,WAAK,MAAM,uBAAuB,eAAe;AAAA,QAC/C,YAAY;AAAA,QACZ,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA,EAGA,aAGE;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,MAAM,mBAAmB,WAAmB;AAC1C,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AAEA,WAAO,KAAK,UAAU,mBAAmB,SAAS;AAAA,EACpD;AAAA,EAEA,MAAM,kBAAkB,WAAmB,QAAiB;AAC1D,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AAEA,WAAO,KAAK,UAAU,kBAAkB,WAAW,MAAM;AAAA,EAC3D;AAAA;AAAA,EAGA,YAAY;AACV,UAAM,aAAa,KAAK,MAAM,kBAAkB;AAEhD,QAAI,CAAC,cAAc,CAAC,KAAK,aAAa;AACpC;AAAA,IACF;AAEA,UAAM,cAAc,CAAC,WAAW;AAEhC,SAAK,YAAY,eAAe,EAAE,QAAQ,CAAC,UAAU;AACnD,YAAM,UAAU;AAAA,IAClB,CAAC;AAED,SAAK,MAAM,uBAAuB;AAAA,MAChC,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MACX,OAAO;AAAA,QACL,YAAY;AAAA,MACd;AAAA,IACF,CAAC;AAED,SAAK,WAAW,UAAU,CAAC,WAAW;AACtC,SAAK,OAAO,eAAe,KAAK,MAAM,WAAW;AAAA,EACnD;AAAA,EAEA,YAAY;AACV,UAAM,aAAa,KAAK,MAAM,kBAAkB;AAEhD,QAAI,CAAC,cAAc,CAAC,KAAK,aAAa;AACpC;AAAA,IACF;AAEA,UAAM,cAAc,CAAC,WAAW;AAEhC,SAAK,YAAY,eAAe,EAAE,QAAQ,CAAC,UAAU;AACnD,YAAM,UAAU;AAAA,IAClB,CAAC;AAED,SAAK,MAAM,uBAAuB;AAAA,MAChC,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MACX,OAAO;AAAA,QACL,YAAY;AAAA,MACd;AAAA,IACF,CAAC;AAED,SAAK,WAAW,UAAU,CAAC,WAAW;AAEtC,SAAK,OAAO,eAAe,KAAK,MAAM,WAAW;AAAA,EACnD;AAAA;AAAA,EAGA,MAAM,mBAAmB;AACvB,QAAI;AACF,UAAI,CAAC,UAAU,cAAc,iBAAiB;AAC5C,cAAM,IAAI,MAAM,6CAA6C;AAAA,MAC/D;AAEA,UAAI,CAAC,KAAK,WAAW;AACnB,cAAM,IAAI,MAAM,gDAAgD;AAAA,MAClE;AAEA,WAAK,eAAe,MAAM,KAAK,UAAU,YAAY;AAErD,WAAK,kBAAkB;AAEvB,WAAK,MAAM,uBAAuB;AAAA,QAChC,OAAO;AAAA,UACL,iBAAiB;AAAA,UACjB,cAAc,KAAK;AAAA,UACnB,aAAa,KAAK,cAAc,eAAe,EAAE,CAAC;AAAA,QACpD;AAAA,MACF,CAAC;AAED,aAAO,KAAK;AAAA,IACd,SAAS,KAAU;AACjB,WAAK;AAAA,QACH;AAAA,QACA,KAAK,WAAW;AAAA,QAChB;AAAA,QACA;AAAA,MACF;AAEA,WAAK,kBAAkB;AACvB,WAAK,eAAe;AAEpB,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,kBAAkB;AACtB,QAAI,CAAC,KAAK,WAAW;AACnB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,KAAK,UAAU,gBAAgB;AAAA,IACvC,UAAE;AACA,WAAK,eAAe;AACpB,WAAK,kBAAkB;AAEvB,WAAK,MAAM,uBAAuB;AAAA,QAChC,OAAO;AAAA,UACL,iBAAiB;AAAA,UACjB,cAAc;AAAA,UACd,aAAa;AAAA,QACf;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,iBAAiB;AACrB,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AAEA,UAAM,KAAK,UAAU,eAAe;AAAA,EACtC;AAAA,EAEA,MAAM,gBAAgB;AACpB,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AAEA,UAAM,KAAK,UAAU,cAAc;AAAA,EACrC;AAAA,EAEA,MAAM,qBAEH;AACD,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AAEA,WAAO,KAAK,UAAU,mBAAmB;AAAA,EAC3C;AAAA;AAAA,EAIA,gBAAgB,SAAoB;AAClC,QAAI,CAAC,KAAK,WAAW;AACnB,cAAQ,KAAK,0BAA0B;AACvC;AAAA,IACF;AAEA,UAAM,UAAU,QAAQ,QAAQ,KAAK;AACrC,QAAI,CAAC,QAAS;AAEd,SAAK,UAAU,gBAAgB;AAAA,MAC7B;AAAA,MACA,UAAU,QAAQ,YAAY;AAAA,MAC9B,QAAQ,QAAQ,UAAU;AAAA,IAC5B,CAAC;AAAA,EACH;AAAA,EAEA,aAAa,UAAwB;AACnC,QAAI,CAAC,KAAK,WAAW;AACnB,cAAQ,KAAK,0BAA0B;AACvC;AAAA,IACF;AACA,SAAK,UAAU,aAAa,QAAQ;AAAA,EACtC;AAAA;AAAA,EAGQ,yBAAyB,eAAuB;AACtD,SAAK,sBAAsB,kBAAkB,aAAa;AAE1D,UAAM,SAAS,KAAK,cAAc,IAAI,aAAa;AAEnD,YAAQ,UAAU,EAAE,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AAEnD,SAAK,cAAc,OAAO,aAAa;AAEvC,UAAM,SAAS,KAAK,oBAAoB,IAAI,aAAa;AAEzD,YAAQ,UAAU,EAAE,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AAEnD,SAAK,oBAAoB,OAAO,aAAa;AAAA,EAC/C;AAAA;AAAA,EAGA,MAAM,aAA4B;AAChC,QAAI,KAAK,mBAAmB;AAC1B,aAAO,KAAK;AAAA,IACd;AAEA,SAAK,oBAAoB,KAAK,kBAAkB;AAEhD,QAAI;AACF,YAAM,KAAK;AAAA,IACb,UAAE;AACA,WAAK,oBAAoB;AAAA,IAC3B;AAAA,EACF;AAAA,EAEA,MAAc,oBAAoB;AAChC,SAAK,wBAAwB;AAC7B,SAAK,cAAc;AAEnB,UAAM,SAAS,KAAK;AACpB,SAAK,YAAY;AAEjB,QAAI,QAAQ;AACV,YAAM,OAAO,MAAM;AAAA,IACrB;AAGA,QAAI,KAAK,aAAa;AACpB,WAAK,YAAY,UAAU,EAAE,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AAE5D,WAAK,cAAc;AAAA,IACrB;AAEA,QAAI,KAAK,cAAc;AACrB,WAAK,aAAa,UAAU,EAAE,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AAC7D,WAAK,eAAe;AAAA,IACtB;AAEA,SAAK,kBAAkB;AAGvB,eAAW,UAAU,KAAK,cAAc,OAAO,GAAG;AAChD,aAAO,UAAU,EAAE,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AAAA,IACpD;AAEA,SAAK,cAAc,MAAM;AACzB,eAAW,UAAU,KAAK,oBAAoB,OAAO,GAAG;AACtD,aAAO,UAAU,EAAE,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AAAA,IACpD;AAEA,SAAK,oBAAoB,MAAM;AAC/B,SAAK,KAAK,KAAK;AACf,SAAK,KAAK,OAAO;AAEjB,SAAK,MAAM,mBAAmB;AAE9B,SAAK,MAAM,OAAO,kBAAkB;AAEpC,SAAK,MAAM,iBAAiB;AAC5B,SAAK,OAAO,gBAAgB;AAAA,EAC9B;AACF;;;AC1oCA,mBAAoC;AAI7B,SAAS,gBACd,cACA,OACA,UACG;AACH,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAS,MAAM,SAAS,YAAY,CAAC;AAE/D,8BAAU,MAAM;AAEd,UAAM,cAAc,aAAa,UAAU,OAAO,MAAM;AACtD,eAAS,SAAS,YAAY,CAAC;AAAA,IACjC,CAAC;AAED,WAAO;AAAA,EACT,GAAG,CAAC,cAAc,OAAO,QAAQ,CAAC;AAElC,SAAO;AACT;;;ANkOI;AAtLJ,IAAM,qBAAiB,6BAA0C,IAAI;AAE9D,IAAM,kBAAkB,CAAC;AAAA,EAC9B;AAAA,EACA;AACF,MAGM;AACJ,QAAM,aAAS,sBAA4B,IAAI;AAC/C,QAAM,qBAAiB,sBAAO,oBAAI,IAAwB,CAAC;AAC3D,QAAM,4BAAwB,sBAAO,oBAAI,IAAwB,CAAC;AAClE,QAAM,6BAAyB;AAAA,IAC7B,oBAAI,IAA4C;AAAA,EAClD;AACA,QAAM,2BAAuB,sBAAO,oBAAI,IAAgB,CAAC;AACzD,QAAM,0BAAsB,sBAAO,oBAAI,IAA0B,CAAC;AAClE,QAAM,gCAA4B,sBAAO,oBAAI,IAA8B,CAAC;AAC5E,QAAM,gCAA4B,sBAAO,oBAAI,IAA8B,CAAC;AAC5E,QAAM,wBAAoB,sBAAO,oBAAI,IAAkC,CAAC;AACxE,QAAM,6BAAyB;AAAA,IAC7B,oBAAI,IAAwC;AAAA,EAC9C;AAEA,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,UAAU,IAAI;AAAA,MACnB;AAAA,QACE,eAAe,OAAO;AAAA,MACxB;AAAA,MACA;AAAA,QACE,SAAS,CAAC,QAAQ;AAChB,yBAAe,QAAQ,QAAQ,CAAC,OAAO,GAAG,GAAG,CAAC;AAAA,QAChD;AAAA,QAEA,kBAAkB,CAAC,QAAQ;AACzB,gCAAsB,QAAQ,QAAQ,CAAC,OAAO,GAAG,GAAG,CAAC;AAAA,QACvD;AAAA,QAEA,kBAAkB,CAAC,GAAG,MAAM;AAC1B,iCAAuB,QAAQ,QAAQ,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC;AAAA,QACzD;AAAA,QAEA,eAAe,MAAM;AACnB,+BAAqB,QAAQ,QAAQ,CAAC,OAAO,GAAG,CAAC;AAAA,QACnD;AAAA,QAEA,qBAAqB,CAAC,UAAU;AAC9B,8BAAoB,QAAQ,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC;AAAA,QACvD;AAAA,QAEA,oBAAoB,CAAC,cAAc;AACjC,oCAA0B,QAAQ,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC;AAAA,QACjE;AAAA,QAEA,oBAAoB,CAAC,cAAc;AACjC,oCAA0B,QAAQ,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC;AAAA,QACjE;AAAA,QAEA,YAAY,CAAC,aAAa;AACxB,4BAAkB,QAAQ,QAAQ,CAAC,OAAO,GAAG,QAAQ,CAAC;AAAA,QACxD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,QAAM,MAAM,OAAO;AACnB,QAAM,mBAAmB;AAAA,IAAgB,IAAI;AAAA,IAAO;AAAA,IAAkB,CAAC,MACrE,MAAM,KAAK,EAAE,gBAAgB;AAAA,EAC/B;AACA,QAAM,cAAc;AAAA,IAClB,IAAI;AAAA,IACJ;AAAA,IACA,CAAC,MAAM,EAAE;AAAA,EACX;AACA,QAAM,eAAe;AAAA,IACnB,IAAI;AAAA,IACJ;AAAA,IACA,CAAC,MAAM,EAAE;AAAA,EACX;AACA,QAAM,mBAAmB;AAAA,IACvB,IAAI;AAAA,IACJ;AAAA,IACA,CAAC,MAAM,EAAE;AAAA,EACX;AACA,QAAM,WAAW;AAAA,IAAgB,IAAI;AAAA,IAAO;AAAA,IAAQ,CAAC,MACnD,EAAE,gBAAgB;AAAA,EACpB;AAEA,QAAM,YAAQ,uBAA6B,MAAM;AAC/C,WAAO;AAAA,MACL;AAAA,MACA,MAAM,CAAC,eACL,IAAI,YAAY;AAAA,QACd,GAAG;AAAA,QACH,GAAG;AAAA,MACL,CAAC;AAAA,MACH,OAAO,MAAM,IAAI,WAAW;AAAA,MAC5B,YAAY,IAAI,WAAW,KAAK,GAAG;AAAA,MACnC,SAAS,IAAI,QAAQ,KAAK,GAAG;AAAA,MAC7B,YAAY,IAAI,WAAW,KAAK,GAAG;AAAA,MACnC,WAAW,IAAI,UAAU,KAAK,GAAG;AAAA,MACjC,WAAW,IAAI,UAAU,KAAK,GAAG;AAAA,MACjC,kBAAkB,IAAI,iBAAiB,KAAK,GAAG;AAAA,MAC/C,iBAAiB,IAAI,gBAAgB,KAAK,GAAG;AAAA,MAC7C,aAAa,IAAI,gBAAgB,KAAK,GAAG;AAAA,MACzC,cAAc,IAAI,aAAa,KAAK,GAAG;AAAA,MAEvC,MAAM,IAAI,WAAW;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,CAAC,UAAuB;AACjC,YAAI,UAAU,eAAe;AAC3B,gBAAM,IAAI,MAAM,iCAAiC,KAAK,GAAG;AAAA,QAC3D;AACA,eAAO;AAAA,UACL,UAAU,IAAI,MAAM,gBAAgB;AAAA,UACpC,SAAS,IAAI,gBAAgB,KAAK,GAAG;AAAA,QACvC;AAAA,MACF;AAAA,MACA,oBAAoB,IAAI,mBAAmB,KAAK,GAAG;AAAA,MACnD,mBAAmB,IAAI,kBAAkB,KAAK,GAAG;AAAA,MACjD,gBAAgB,IAAI,eAAe,KAAK,GAAG;AAAA,MAC3C,eAAe,IAAI,cAAc,KAAK,GAAG;AAAA,MACzC,oBAAoB,IAAI,mBAAmB,KAAK,GAAG;AAAA,MAEnD,SAAS,CAAC,OAA2B;AACnC,uBAAe,QAAQ,IAAI,EAAE;AAE7B,eAAO,MAAM;AACX,yBAAe,QAAQ,OAAO,EAAE;AAAA,QAClC;AAAA,MACF;AAAA,MAEA,kBAAkB,CAAC,OAA2B;AAC5C,8BAAsB,QAAQ,IAAI,EAAE;AAEpC,eAAO,MAAM;AACX,gCAAsB,QAAQ,OAAO,EAAE;AAAA,QACzC;AAAA,MACF;AAAA,MACA,kBAAkB,CAAC,OAA2B;AAC5C,+BAAuB,QAAQ,IAAI,EAAE;AAErC,eAAO,MAAM;AACX,iCAAuB,QAAQ,OAAO,EAAE;AAAA,QAC1C;AAAA,MACF;AAAA,MACA,eAAe,CAAC,OAAmB;AACjC,6BAAqB,QAAQ,IAAI,EAAE;AACnC,eAAO,MAAM;AACX,+BAAqB,QAAQ,OAAO,EAAE;AAAA,QACxC;AAAA,MACF;AAAA,MACA,qBAAqB,CAAC,OAA6B;AACjD,4BAAoB,QAAQ,IAAI,EAAE;AAClC,eAAO,MAAM,oBAAoB,QAAQ,OAAO,EAAE;AAAA,MACpD;AAAA,MACA,oBAAoB,CAAC,OAAiC;AACpD,kCAA0B,QAAQ,IAAI,EAAE;AACxC,eAAO,MAAM,0BAA0B,QAAQ,OAAO,EAAE;AAAA,MAC1D;AAAA,MACA,oBAAoB,CAAC,OAAiC;AACpD,kCAA0B,QAAQ,IAAI,EAAE;AACxC,eAAO,MAAM,0BAA0B,QAAQ,OAAO,EAAE;AAAA,MAC1D;AAAA,MACA,YAAY,CAAC,OAAqC;AAChD,0BAAkB,QAAQ,IAAI,EAAE;AAChC,eAAO,MAAM,kBAAkB,QAAQ,OAAO,EAAE;AAAA,MAClD;AAAA,MACA,yBAAyB,CAAC,OAAO;AAC/B,+BAAuB,QAAQ,IAAI,EAAE;AAErC,eAAO,MAAM;AACX,iCAAuB,QAAQ,OAAO,EAAE;AAAA,QAC1C;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,QAAQ,KAAK,kBAAkB,cAAc,UAAU,WAAW,CAAC;AAEvE,SACE,4CAAC,eAAe,UAAf,EAAwB,OAAe,UAAS;AAErD;AAEO,IAAM,oBAAoB,MAAM;AACrC,QAAM,UAAM,0BAAW,cAAc;AACrC,MAAI,CAAC;AACH,UAAM,IAAI,MAAM,yDAAyD;AAC3E,SAAO;AACT;;;AD5PO,IAAM,sBAAsB,MAAM;AACvC,QAAM,EAAE,IAAI,IAAI,kBAAkB;AAGlC,QAAM,CAAC,kBAAkB,mBAAmB,QAAI;AAAA,IAC9C,MAAM;AACJ,YAAM,UAAU,IAAI,MAAM;AAC1B,aAAO,WAAW,QAAQ,KAAM,UAA0B;AAAA,IAC5D;AAAA,EACF;AAEA,+BAAU,MAAM;AACd,UAAM,cAAc,IAAI,MAAM,UAAU,oBAAoB,MAAM;AAChE,YAAM,UAAU,IAAI,MAAM;AAG1B,UAAI,WAAW,QAAQ,IAAI;AACzB,4BAAoB,EAAE,GAAG,QAAQ,CAAgB;AAAA,MACnD,OAAO;AACL,4BAAoB,IAAI;AAAA,MAC1B;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT,GAAG,CAAC,GAAG,CAAC;AAER,QAAM,oBAAgB,sBAA2B,IAAI;AAErD,QAAM,eAAW;AAAA,IACf,CAAC,UAAmC;AAClC,UAAI,CAAC,MAAO;AAEZ,YAAM,SAAS,kBAAkB,OAAO;AACxC,UAAI,CAAC,OAAQ;AAEb,UAAI,cAAc,YAAY,OAAQ;AACtC,oBAAc,UAAU;AAExB,YAAM,YAAY;AAClB,YAAM,WAAW;AACjB,YAAM,cAAc;AAEpB,YAAM,KAAK,EAAE,MAAM,CAAC,QAAQ;AAC1B,gBAAQ,KAAK,mCAAmC,GAAG;AAAA,MACrD,CAAC;AAAA,IACH;AAAA,IACA,CAAC,kBAAkB,OAAO,MAAM;AAAA,EAClC;AAEA,SAAO;AAAA,IACL,aAAa;AAAA,IACb;AAAA,EACF;AACF;;;AQzDA,IAAAC,gBAA0B;AAGnB,IAAM,aAAa,CAAC,aAUrB;AACJ,QAAM,MAAM,kBAAkB;AAG9B,+BAAU,MAAM;AACd,QAAI,CAAC,UAAU,QAAS;AACxB,WAAO,IAAI,QAAQ,SAAS,OAAO;AAAA,EACrC,GAAG,CAAC,UAAU,OAAO,CAAC;AAEtB,+BAAU,MAAM;AACd,QAAI,CAAC,UAAU,wBAAyB;AAExC,WAAO,IAAI,wBAAwB,SAAS,uBAAuB;AAAA,EACrE,GAAG,CAAC,UAAU,uBAAuB,CAAC;AAGtC,+BAAU,MAAM;AACd,QAAI,CAAC,UAAU,iBAAkB;AACjC,WAAO,IAAI,iBAAiB,SAAS,gBAAgB;AAAA,EACvD,GAAG,CAAC,UAAU,gBAAgB,CAAC;AAG/B,+BAAU,MAAM;AACd,QAAI,CAAC,UAAU,iBAAkB;AACjC,WAAO,IAAI,iBAAiB,SAAS,gBAAgB;AAAA,EACvD,GAAG,CAAC,UAAU,gBAAgB,CAAC;AAG/B,+BAAU,MAAM;AACd,QAAI,CAAC,UAAU,cAAe;AAC9B,WAAO,IAAI,cAAc,SAAS,aAAa;AAAA,EACjD,GAAG,CAAC,UAAU,aAAa,CAAC;AAE5B,+BAAU,MAAM;AACd,QAAI,CAAC,UAAU,oBAAqB;AACpC,WAAO,IAAI,oBAAoB,SAAS,mBAAmB;AAAA,EAC7D,GAAG,CAAC,UAAU,mBAAmB,CAAC;AAElC,+BAAU,MAAM;AACd,QAAI,CAAC,UAAU,mBAAoB;AACnC,WAAO,IAAI,mBAAmB,SAAS,kBAAkB;AAAA,EAC3D,GAAG,CAAC,UAAU,kBAAkB,CAAC;AAEjC,+BAAU,MAAM;AACd,QAAI,CAAC,UAAU,mBAAoB;AACnC,WAAO,IAAI,mBAAmB,SAAS,kBAAkB;AAAA,EAC3D,GAAG,CAAC,UAAU,kBAAkB,CAAC;AAEjC,+BAAU,MAAM;AACd,QAAI,CAAC,UAAU,WAAY;AAC3B,WAAO,IAAI,WAAW,SAAS,UAAU;AAAA,EAC3C,GAAG,CAAC,UAAU,UAAU,CAAC;AAEzB,QAAM,EAAE,KAAK,GAAG,GAAG,UAAU,IAAI;AACjC,SAAO;AACT;;;ACpEA,IAAAC,gBAAoC;AAI7B,IAAM,kBAAkB,MAAM;AACnC,QAAM,EAAE,IAAI,IAAI,kBAAkB;AAElC,QAAM,CAAC,cAAc,eAAe,QAAI;AAAA,IAAwB,MAC9D,IAAI,MAAM,gBAAgB;AAAA,EAC5B;AAEA,+BAAU,MAAM;AACd,UAAM,SAAS,MAAM;AACnB,sBAAgB,IAAI,MAAM,gBAAgB,CAAC;AAAA,IAC7C;AAEA,WAAO;AAEP,UAAM,QAAQ,IAAI,MAAM,UAAU,gBAAgB,MAAM;AAExD,WAAO;AAAA,EACT,GAAG,CAAC,GAAG,CAAC;AAER,SAAO;AACT;;;ACxBA,IAAAC,gBAA4C;AAIrC,IAAM,iBAAiB,CAAC,kBAA0B;AACvD,QAAM,EAAE,IAAI,IAAI,kBAAkB;AAClC,QAAM,eAAW,sBAAgC,IAAI;AACrD,QAAM,eAAW,sBAAgC,IAAI;AAErD,QAAM,CAAC,aAAa,cAAc,QAAI;AAAA,IACpC,MAAM,IAAI,MAAM,eAAe,aAAa,KAAK;AAAA,EACnD;AAEA,+BAAU,MAAM;AACd,UAAM,QAAQ,IAAI,MAAM,UAAU,eAAe,aAAa,IAAI,MAAM;AACtE,YAAM,IAAI,IAAI,MAAM,eAAe,aAAa;AAChD,qBAAe,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI;AAAA,IACpC,CAAC;AAED,WAAO;AAAA,EACT,GAAG,CAAC,eAAe,GAAG,CAAC;AAEvB,+BAAU,MAAM;AACd,UAAM,SAAS,aAAa,OAAO;AACnC,QAAI,CAAC,OAAQ;AAGb,QAAI,SAAS,SAAS;AACpB,eAAS,QAAQ,YAAY;AAC7B,eAAS,QAAQ,QAAQ;AACzB,eAAS,QAAQ,cAAc;AAC/B,eAAS,QAAQ,KAAK,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IACxC;AAGA,QAAI,SAAS,SAAS;AACpB,eAAS,QAAQ,YAAY;AAC7B,eAAS,QAAQ,KAAK,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IACxC;AAAA,EACF,GAAG,CAAC,aAAa,OAAO,MAAM,CAAC;AAE/B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,aAAa,CAAC,CAAC,aAAa,OAAO;AAAA,IACnC,cAAc,CAAC,CAAC,aAAa,OAAO;AAAA,IACpC,iBAAiB,aAAa;AAAA,EAChC;AACF;;;AChDA,IAAAC,gBAAoC;AAgC7B,SAAS,kBAAkB,QAAgB,eAAuB;AACvE,QAAM,CAAC,MAAM,OAAO,QAAI,wBAA+B,IAAI;AAC3D,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAwB,IAAI;AACtD,QAAM,CAAC,aAAa,cAAc,QAAI,wBAAS,KAAK;AACpD,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,IAAI;AAE/C,+BAAU,MAAM;AACd,QAAI,CAAC,QAAQ;AACX,mBAAa,KAAK;AAClB;AAAA,IACF;AAEA,QAAI,UAAU;AACd,QAAI,QAA8C;AAElD,UAAM,OAAO,YAAY;AACvB,UAAI;AACF,cAAM,WAAW,MAAM;AAAA,UACrB,GAAG,WAAW,OAAO,UAAU,mBAAmB,MAAM,CAAC;AAAA,QAC3D;AAEA,YAAI,CAAC,SAAS,IAAI;AAChB,gBAAM,IAAI,MAAM,uBAAuB,SAAS,MAAM,GAAG;AAAA,QAC3D;AAEA,cAAM,OAAO,MAAM,SAAS,KAAK;AACjC,YAAI,QAAS;AAEb,gBAAQ;AAAA,UACN,QAAQ;AAAA;AAAA;AAAA,UAGR,OAAO;AAAA,UACP,SAAS,CAAC,KAAK;AAAA,UACf,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,qBAAqB;AAAA,UACrB,cAAc,CAAC;AAAA,UACf,MAAM;AAAA,YACJ,IAAI,KAAK;AAAA,YACT,MAAM,KAAK;AAAA,YACX,WAAW,KAAK;AAAA,YAChB,UAAU,KAAK;AAAA,YACf,YAAY,KAAK;AAAA,UACnB;AAAA,QACF,CAAC;AACD,iBAAS,IAAI;AACb,uBAAe,IAAI;AACnB,qBAAa,KAAK;AAAA,MACpB,SAAS,KAAU;AACjB,YAAI,QAAS;AACb,iBAAS,KAAK,WAAW,qBAAqB;AAC9C,uBAAe,KAAK;AACpB,qBAAa,KAAK;AAAA,MACpB,UAAE;AACA,YAAI,CAAC,SAAS;AACZ,kBAAQ,WAAW,MAAM,GAAI;AAAA,QAC/B;AAAA,MACF;AAAA,IACF;AAEA,SAAK,KAAK;AAEV,WAAO,MAAM;AACX,gBAAU;AACV,UAAI,MAAO,cAAa,KAAK;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,CAAC;AAE1B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":["import_react","import_react","message","import_react","import_react","import_react","import_react"]}
|