@z-api/call 1.0.0-staging.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"z-api-call.global.js","sources":["../src/core/EventEmitter.ts","../src/core/CallWebSocket.ts","../src/utils/pcm.ts","../src/core/AudioEngine.ts","../src/core/VideoEngine.ts","../src/core/CallState.ts","../src/widget/CallWidget.css.ts","../src/widget/icons.ts","../src/utils/format.ts","../src/widget/CallWidget.ts","../src/core/ZAPICallClient.ts","../src/types.ts","../src/index.ts"],"sourcesContent":["type Listener = (...args: any[]) => void;\n\nexport class EventEmitter<Events extends { [K in keyof Events]: Listener }> {\n private listeners = new Map<keyof Events, Set<Listener>>();\n\n on<K extends keyof Events>(event: K, listener: Events[K]): this {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener as Listener);\n return this;\n }\n\n off<K extends keyof Events>(event: K, listener: Events[K]): this {\n this.listeners.get(event)?.delete(listener as Listener);\n return this;\n }\n\n protected emit<K extends keyof Events>(event: K, ...args: Parameters<Events[K]>): void {\n const set = this.listeners.get(event);\n if (!set) return;\n for (const listener of set) {\n try {\n listener(...args);\n } catch (e) {\n console.error(`[ZAPICall] Event listener error (${String(event)}):`, e);\n }\n }\n }\n\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","import type { WsServerMessage } from '../types';\n\nexport type OnJsonMessage = (msg: WsServerMessage) => void;\nexport type OnBinaryMessage = (data: ArrayBuffer) => void;\nexport type OnConnectionChange = (connected: boolean) => void;\n\nconst INITIAL_RECONNECT_MS = 1000;\nconst MAX_RECONNECT_MS = 30000;\nconst PING_INTERVAL_MS = 25000;\n\nexport class CallWebSocket {\n private ws: WebSocket | null = null;\n private baseUrl: string;\n private instanceId: string;\n private getToken: () => Promise<string>;\n private reconnectMs = INITIAL_RECONNECT_MS;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private pingTimer: ReturnType<typeof setInterval> | null = null;\n private destroyed = false;\n\n onJson: OnJsonMessage = () => {};\n onBinary: OnBinaryMessage = () => {};\n onConnectionChange: OnConnectionChange = () => {};\n\n constructor(baseUrl: string, instanceId: string, getToken: () => Promise<string>) {\n this.baseUrl = baseUrl;\n this.instanceId = instanceId;\n this.getToken = getToken;\n }\n\n private buildUrl(token: string): string {\n const u = new URL(this.baseUrl);\n u.protocol = u.protocol === 'https:' ? 'wss:' : 'ws:';\n u.pathname = '/ws/call';\n u.searchParams.set('instance', this.instanceId);\n u.searchParams.set('token', token);\n return u.toString();\n }\n\n async connect(): Promise<void> {\n if (this.destroyed) return;\n this.cleanup();\n\n let token: string;\n try {\n token = await this.getToken();\n } catch (e) {\n console.warn('[ZAPICall] Failed to get token:', e);\n this.scheduleReconnect();\n return;\n }\n\n if (this.destroyed) return;\n\n const url = this.buildUrl(token);\n console.log('[ZAPICall] Connecting to', url);\n\n const ws = new WebSocket(url);\n ws.binaryType = 'arraybuffer';\n this.ws = ws;\n\n ws.onopen = () => {\n console.log('[ZAPICall] WebSocket connected');\n this.reconnectMs = INITIAL_RECONNECT_MS;\n this.onConnectionChange(true);\n this.startPing();\n };\n\n ws.onmessage = (event) => {\n if (typeof event.data === 'string') {\n try {\n const parsed = JSON.parse(event.data) as WsServerMessage;\n console.log('[ZAPICall] <<', parsed.type, parsed);\n this.onJson(parsed);\n } catch {}\n } else if (event.data instanceof ArrayBuffer) {\n this.onBinary(event.data);\n }\n };\n\n ws.onclose = (event) => {\n console.log('[ZAPICall] WebSocket closed:', event.code, event.reason);\n this.stopPing();\n this.onConnectionChange(false);\n if (event.code === 4001) {\n console.warn('[ZAPICall] Invalid credentials (4001), not reconnecting');\n return;\n }\n this.scheduleReconnect();\n };\n\n ws.onerror = (event) => {\n console.warn('[ZAPICall] WebSocket error:', event);\n };\n }\n\n send(data: string | ArrayBuffer): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.ws.send(data);\n }\n }\n\n sendJson(msg: Record<string, unknown>): void {\n this.send(JSON.stringify(msg));\n }\n\n isConnected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n destroy(): void {\n this.destroyed = true;\n this.cleanup();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n\n private cleanup(): void {\n this.stopPing();\n if (this.ws) {\n this.ws.onopen = null;\n this.ws.onmessage = null;\n this.ws.onclose = null;\n this.ws.onerror = null;\n if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.close();\n }\n this.ws = null;\n }\n }\n\n private scheduleReconnect(): void {\n if (this.destroyed) return;\n this.reconnectTimer = setTimeout(() => {\n this.connect();\n }, this.reconnectMs);\n this.reconnectMs = Math.min(this.reconnectMs * 2, MAX_RECONNECT_MS);\n }\n\n private startPing(): void {\n this.pingTimer = setInterval(() => {\n this.sendJson({ type: 'ping' });\n }, PING_INTERVAL_MS);\n }\n\n private stopPing(): void {\n if (this.pingTimer) {\n clearInterval(this.pingTimer);\n this.pingTimer = null;\n }\n }\n}\n","/** Convert Int16LE array to Float32 [-1, 1] for Web Audio playback */\nexport function int16ToFloat32(int16: Int16Array): Float32Array {\n const float32 = new Float32Array(int16.length);\n for (let i = 0; i < int16.length; i++) {\n float32[i] = int16[i] / 32768;\n }\n return float32;\n}\n\n/** Convert Float32 [-1, 1] to Int16LE for sending mic audio */\nexport function float32ToInt16(float32: Float32Array): Int16Array {\n const int16 = new Int16Array(float32.length);\n for (let i = 0; i < float32.length; i++) {\n let s = float32[i];\n if (s > 1) s = 1;\n else if (s < -1) s = -1;\n int16[i] = Math.round(s * 32767);\n }\n return int16;\n}\n\n/** Calculate RMS level (0-1) from Float32 samples */\nexport function calculateRmsLevel(samples: Float32Array): number {\n if (samples.length === 0) return 0;\n let sum = 0;\n for (let i = 0; i < samples.length; i++) {\n sum += samples[i] * samples[i];\n }\n return Math.sqrt(sum / samples.length);\n}\n","import { int16ToFloat32, float32ToInt16, calculateRmsLevel } from '../utils/pcm';\n\nconst SCHEDULE_AHEAD_S = 0.02;\nconst MAX_QUEUE_S = 0.15;\n\nexport type OnMicData = (pcmInt16: ArrayBuffer) => void;\nexport type OnAudioLevel = (level: number) => void;\n\nexport class AudioEngine {\n private playbackCtx: AudioContext | null = null;\n private micCtx: AudioContext | null = null;\n private micStream: MediaStream | null = null;\n private micProcessor: ScriptProcessorNode | null = null;\n private micSource: MediaStreamAudioSourceNode | null = null;\n private nextPlayTime = 0;\n private sampleRate: number;\n private destroyed = false;\n\n onMicData: OnMicData = () => {};\n onAudioLevel: OnAudioLevel = () => {};\n\n constructor(sampleRate = 48000) {\n this.sampleRate = sampleRate;\n }\n\n /** Play received PCM Int16LE audio */\n private playLogCount = 0;\n\n playPcm(data: ArrayBuffer): void {\n if (this.destroyed || data.byteLength === 0) return;\n\n if (!this.playbackCtx) {\n this.playbackCtx = new AudioContext({ sampleRate: this.sampleRate });\n this.nextPlayTime = this.playbackCtx.currentTime;\n }\n\n if (this.playbackCtx.state === 'suspended') {\n this.playbackCtx.resume();\n }\n\n this.playLogCount++;\n if (this.playLogCount <= 5 || this.playLogCount % 250 === 0) {\n const int16Preview = new Int16Array(data);\n let maxVal = 0;\n for (let i = 0; i < Math.min(int16Preview.length, 100); i++) {\n const abs = Math.abs(int16Preview[i]);\n if (abs > maxVal) maxVal = abs;\n }\n console.log(`[AudioEngine] playPcm #${this.playLogCount} bytes=${data.byteLength} ctxState=${this.playbackCtx.state} sampleRate=${this.sampleRate} maxSample=${maxVal} nextPlayT=${this.nextPlayTime.toFixed(3)} ctxTime=${this.playbackCtx.currentTime.toFixed(3)}`);\n }\n\n const int16 = new Int16Array(data);\n const float32 = int16ToFloat32(int16);\n\n // Emit audio level\n const level = calculateRmsLevel(float32);\n this.onAudioLevel(level);\n\n // Schedule playback\n const buffer = this.playbackCtx.createBuffer(1, float32.length, this.sampleRate);\n buffer.getChannelData(0).set(float32);\n\n const source = this.playbackCtx.createBufferSource();\n source.buffer = buffer;\n source.connect(this.playbackCtx.destination);\n\n const now = this.playbackCtx.currentTime;\n if (this.nextPlayTime < now) {\n this.nextPlayTime = now + SCHEDULE_AHEAD_S;\n } else if (this.nextPlayTime - now > MAX_QUEUE_S) {\n this.nextPlayTime = now + SCHEDULE_AHEAD_S;\n }\n source.start(this.nextPlayTime);\n this.nextPlayTime += buffer.duration;\n }\n\n /** Start capturing microphone audio and sending as PCM Int16LE */\n async startMic(): Promise<void> {\n if (this.destroyed || this.micStream) return;\n\n this.micStream = await navigator.mediaDevices.getUserMedia({\n audio: {\n sampleRate: this.sampleRate,\n channelCount: 1,\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n },\n });\n\n this.micCtx = new AudioContext({ sampleRate: this.sampleRate });\n this.micSource = this.micCtx.createMediaStreamSource(this.micStream);\n\n // ScriptProcessorNode: 4096 samples per frame\n this.micProcessor = this.micCtx.createScriptProcessor(4096, 1, 1);\n this.micProcessor.onaudioprocess = (e) => {\n if (this.destroyed) return;\n const float32 = e.inputBuffer.getChannelData(0);\n const int16 = float32ToInt16(float32);\n this.onMicData(int16.buffer as ArrayBuffer);\n };\n\n this.micSource.connect(this.micProcessor);\n this.micProcessor.connect(this.micCtx.destination);\n }\n\n stopMic(): void {\n if (this.micProcessor) {\n this.micProcessor.disconnect();\n this.micProcessor = null;\n }\n if (this.micSource) {\n this.micSource.disconnect();\n this.micSource = null;\n }\n if (this.micStream) {\n for (const track of this.micStream.getTracks()) {\n track.stop();\n }\n this.micStream = null;\n }\n if (this.micCtx) {\n this.micCtx.close().catch(() => {});\n this.micCtx = null;\n }\n }\n\n /** Resume AudioContext (must be called from user gesture for autoplay policy) */\n resume(): void {\n if (!this.playbackCtx) {\n this.playbackCtx = new AudioContext({ sampleRate: this.sampleRate });\n this.nextPlayTime = this.playbackCtx.currentTime;\n }\n if (this.playbackCtx.state === 'suspended') {\n this.playbackCtx.resume();\n }\n }\n\n destroy(): void {\n this.destroyed = true;\n this.stopMic();\n if (this.playbackCtx) {\n this.playbackCtx.close().catch(() => {});\n this.playbackCtx = null;\n }\n }\n}\n","import type { VideoFrameInfo } from '../types';\n\nconst H264_FORMAT = 100;\nconst H264_CODEC = 'avc1.42001E';\nconst MAX_DECODER_ERRORS = 5;\n\nexport class VideoEngine {\n private canvas: HTMLCanvasElement | null = null;\n private ctx: CanvasRenderingContext2D | null = null;\n private localVideo: HTMLVideoElement | null = null;\n private localStream: MediaStream | null = null;\n private captureCanvas: HTMLCanvasElement | null = null;\n private captureCtx: CanvasRenderingContext2D | null = null;\n private tempCanvas: HTMLCanvasElement | null = null;\n private tempCtx: CanvasRenderingContext2D | null = null;\n private captureInterval: ReturnType<typeof setInterval> | null = null;\n private h264Decoder: VideoDecoder | null = null;\n private h264ErrorCount = 0;\n private orientationMap = new Map<number, number>();\n\n onCameraFrame: ((rgba: ArrayBuffer, width: number, height: number) => void) | null = null;\n onEncodedCameraFrame: ((h264: ArrayBuffer, width: number, height: number, timestampSec: number, isKeyFrame: boolean, latencyMs: number) => void) | null = null;\n private h264Encoder: VideoEncoder | null = null;\n private encoderKeyFrameInterval = 3000;\n private lastKeyFrameTs = 0;\n private h264NeedKeyFrame = false;\n\n setRemoteCanvas(canvas: HTMLCanvasElement): void {\n this.canvas = canvas;\n this.ctx = canvas.getContext('2d');\n }\n\n renderFrame(frame: VideoFrameInfo): void {\n if (!this.canvas || !this.ctx) return;\n const { width, height, data, orientation, format, isKeyFrame, timestamp } = frame;\n if (width <= 0 || height <= 0) return;\n\n if (format === H264_FORMAT) {\n this.decodeH264Frame(data, width, height, orientation, isKeyFrame, timestamp);\n return;\n }\n\n this.renderNV12Frame(data, width, height, orientation);\n }\n\n private h264GotKeyFrame = false;\n private h264FrameIndex = 0;\n\n private decodeH264Frame(\n data: ArrayBuffer, _width: number, _height: number,\n orientation: number, isKeyFrame: boolean, timestamp: number,\n ): void {\n if (data.byteLength === 0) return;\n\n if (!this.h264GotKeyFrame) {\n if (!isKeyFrame) return;\n this.h264GotKeyFrame = true;\n }\n\n if (!this.h264Decoder || this.h264Decoder.state === 'closed') {\n if (this.h264ErrorCount >= MAX_DECODER_ERRORS) return;\n this.h264Decoder = this.createH264Decoder();\n if (!this.h264Decoder) return;\n this.h264GotKeyFrame = false;\n if (!isKeyFrame) return;\n this.h264GotKeyFrame = true;\n }\n\n this.h264FrameIndex++;\n const tsUs = this.h264FrameIndex * 66666;\n this.orientationMap.set(tsUs, orientation);\n\n try {\n this.h264Decoder.decode(new EncodedVideoChunk({\n type: isKeyFrame ? 'key' : 'delta',\n timestamp: tsUs,\n data,\n }));\n } catch (e) {\n this.h264ErrorCount++;\n this.h264GotKeyFrame = false;\n }\n }\n\n private createH264Decoder(): VideoDecoder | null {\n if (typeof globalThis.VideoDecoder !== 'function') return null;\n\n try {\n const decoder = new VideoDecoder({\n output: (vf) => {\n try {\n if (!this.canvas || !this.ctx) { vf.close(); return; }\n const orientation = this.orientationMap.get(vf.timestamp) ?? 1;\n this.orientationMap.delete(vf.timestamp);\n\n const w = vf.codedWidth;\n const h = vf.codedHeight;\n const isRotated = orientation === 2 || orientation === 4;\n const displayW = isRotated ? h : w;\n const displayH = isRotated ? w : h;\n\n if (this.canvas.width !== displayW || this.canvas.height !== displayH) {\n this.canvas.width = displayW;\n this.canvas.height = displayH;\n }\n\n this.ctx!.save();\n if (orientation === 2) {\n this.ctx!.translate(displayW, 0);\n this.ctx!.rotate(Math.PI / 2);\n } else if (orientation === 3) {\n this.ctx!.translate(displayW, displayH);\n this.ctx!.rotate(Math.PI);\n } else if (orientation === 4) {\n this.ctx!.translate(0, displayH);\n this.ctx!.rotate(-Math.PI / 2);\n }\n this.ctx!.drawImage(vf, 0, 0);\n this.ctx!.restore();\n } finally {\n vf.close();\n }\n },\n error: () => {\n this.h264ErrorCount++;\n this.orientationMap.clear();\n },\n });\n\n decoder.configure({ codec: H264_CODEC, optimizeForLatency: true });\n this.h264ErrorCount = 0;\n return decoder;\n } catch {\n return null;\n }\n }\n\n private renderNV12Frame(data: ArrayBuffer, width: number, height: number, orientation: number): void {\n if (!this.canvas || !this.ctx) return;\n\n const isRotated = orientation === 2 || orientation === 4;\n const displayW = isRotated ? height : width;\n const displayH = isRotated ? width : height;\n\n if (this.canvas.width !== displayW || this.canvas.height !== displayH) {\n this.canvas.width = displayW;\n this.canvas.height = displayH;\n }\n\n if (typeof (globalThis as any).VideoFrame === 'function') {\n try {\n const vf = new (globalThis as any).VideoFrame(new Uint8Array(data), {\n format: 'NV12',\n codedWidth: width,\n codedHeight: height,\n timestamp: 0,\n });\n this.ctx.save();\n if (orientation === 2) {\n this.ctx.translate(displayW, 0);\n this.ctx.rotate(Math.PI / 2);\n } else if (orientation === 3) {\n this.ctx.translate(displayW, displayH);\n this.ctx.rotate(Math.PI);\n } else if (orientation === 4) {\n this.ctx.translate(0, displayH);\n this.ctx.rotate(-Math.PI / 2);\n }\n this.ctx.drawImage(vf, 0, 0);\n this.ctx.restore();\n vf.close();\n return;\n } catch {\n // fallback\n }\n }\n\n const nv12 = new Uint8Array(data);\n const rgba = this.nv12ToRgba(nv12, width, height);\n const imgData = new ImageData(new Uint8ClampedArray(rgba.buffer as ArrayBuffer), width, height);\n\n if (orientation >= 2 && orientation <= 4) {\n if (!this.tempCanvas) {\n this.tempCanvas = document.createElement('canvas');\n this.tempCtx = this.tempCanvas.getContext('2d');\n }\n this.tempCanvas.width = width;\n this.tempCanvas.height = height;\n this.tempCtx!.putImageData(imgData, 0, 0);\n\n this.ctx.save();\n if (orientation === 2) {\n this.ctx.translate(displayW, 0);\n this.ctx.rotate(Math.PI / 2);\n } else if (orientation === 3) {\n this.ctx.translate(displayW, displayH);\n this.ctx.rotate(Math.PI);\n } else if (orientation === 4) {\n this.ctx.translate(0, displayH);\n this.ctx.rotate(-Math.PI / 2);\n }\n this.ctx.drawImage(this.tempCanvas, 0, 0);\n this.ctx.restore();\n } else {\n this.ctx.putImageData(imgData, 0, 0);\n }\n }\n\n async startCamera(videoEl: HTMLVideoElement, width = 640, height = 480, fps = 15): Promise<void> {\n this.localVideo = videoEl;\n\n const stream = await navigator.mediaDevices.getUserMedia({\n video: { width: { ideal: width }, height: { ideal: height }, frameRate: { ideal: fps } },\n audio: false,\n });\n this.localStream = stream;\n videoEl.srcObject = stream;\n videoEl.muted = true;\n await videoEl.play();\n\n const useH264 = this.canUseH264Encoder();\n if (useH264) {\n this.startH264Capture(stream, width, height, fps);\n } else {\n this.captureCanvas = document.createElement('canvas');\n this.captureCanvas.width = width;\n this.captureCanvas.height = height;\n this.captureCtx = this.captureCanvas.getContext('2d', { willReadFrequently: true });\n this.captureInterval = setInterval(() => this.captureFrameRaw(), Math.floor(1000 / fps));\n }\n }\n\n stopCamera(): void {\n if (this.captureInterval) {\n clearInterval(this.captureInterval);\n this.captureInterval = null;\n }\n if (this.h264Encoder && this.h264Encoder.state !== 'closed') {\n try { this.h264Encoder.close(); } catch {}\n }\n this.h264Encoder = null;\n if (this.localStream) {\n this.localStream.getTracks().forEach(t => t.stop());\n this.localStream = null;\n }\n if (this.localVideo) {\n this.localVideo.srcObject = null;\n this.localVideo = null;\n }\n this.captureCanvas = null;\n this.captureCtx = null;\n }\n\n private canUseH264Encoder(): boolean {\n return typeof globalThis.VideoEncoder === 'function'\n && typeof (globalThis as any).MediaStreamTrackProcessor === 'function';\n }\n\n private startH264Capture(stream: MediaStream, width: number, height: number, fps: number): void {\n const track = stream.getVideoTracks()[0];\n if (!track) return;\n\n let encodeW = width;\n let encodeH = height;\n let frameCount = 0;\n const submitTimes = new Map<number, number>();\n\n this.h264Encoder = new VideoEncoder({\n output: (chunk, meta) => {\n if (!this.onEncodedCameraFrame) return;\n const buf = new ArrayBuffer(chunk.byteLength);\n chunk.copyTo(buf);\n const isKey = chunk.type === 'key';\n const codedW = meta?.decoderConfig?.codedWidth ?? encodeW;\n const codedH = meta?.decoderConfig?.codedHeight ?? encodeH;\n let latencyMs = 0;\n const submitted = submitTimes.get(chunk.timestamp);\n if (submitted != null) {\n submitTimes.delete(chunk.timestamp);\n latencyMs = Date.now() - submitted;\n }\n const tsSec = chunk.timestamp / 1e3;\n this.onEncodedCameraFrame(buf, codedW, codedH, tsSec, isKey, latencyMs);\n },\n error: (e) => { console.error('[VideoEngine] encoder error:', e); },\n });\n\n this.h264Encoder.configure({\n codec: 'avc1.42001f',\n width: encodeW,\n height: encodeH,\n bitrate: 500000,\n framerate: fps,\n latencyMode: 'realtime',\n bitrateMode: 'constant',\n avc: { format: 'annexb' },\n } as any);\n\n const processor = new (globalThis as any).MediaStreamTrackProcessor({ track });\n const reader = processor.readable.getReader();\n\n const readLoop = async () => {\n while (this.h264Encoder && this.h264Encoder.state !== 'closed') {\n try {\n const { value: frame, done } = await reader.read();\n if (done || !frame) break;\n if (this.h264Encoder.state !== 'configured') { frame.close(); continue; }\n\n const now = Date.now();\n const sinceLastKey = now - this.lastKeyFrameTs;\n const needKey = this.h264NeedKeyFrame || sinceLastKey >= this.encoderKeyFrameInterval || frameCount === 0;\n\n submitTimes.set(frame.timestamp, now);\n this.h264Encoder.encode(frame, { keyFrame: needKey });\n frame.close();\n\n frameCount++;\n if (needKey) {\n this.lastKeyFrameTs = now;\n this.h264NeedKeyFrame = false;\n }\n } catch { break; }\n }\n };\n readLoop();\n }\n\n private captureFrameRaw(): void {\n if (!this.captureCtx || !this.captureCanvas || !this.localVideo || !this.onCameraFrame) return;\n if (this.localVideo.readyState < 2) return;\n\n const w = this.captureCanvas.width;\n const h = this.captureCanvas.height;\n this.captureCtx.drawImage(this.localVideo, 0, 0, w, h);\n const imgData = this.captureCtx.getImageData(0, 0, w, h);\n this.onCameraFrame(imgData.data.buffer, w, h);\n }\n\n private nv12ToRgba(nv12: Uint8Array, width: number, height: number): Uint8ClampedArray {\n const rgba = new Uint8ClampedArray(width * height * 4);\n const yPlaneSize = width * height;\n\n for (let j = 0; j < height; j++) {\n for (let i = 0; i < width; i++) {\n const yIdx = j * width + i;\n const uvIdx = yPlaneSize + (j >> 1) * width + (i & ~1);\n\n const y = nv12[yIdx];\n const u = nv12[uvIdx] - 128;\n const v = nv12[uvIdx + 1] - 128;\n\n const rgbaIdx = yIdx * 4;\n rgba[rgbaIdx] = clamp(y + 1.402 * v);\n rgba[rgbaIdx + 1] = clamp(y - 0.344 * u - 0.714 * v);\n rgba[rgbaIdx + 2] = clamp(y + 1.772 * u);\n rgba[rgbaIdx + 3] = 255;\n }\n }\n return rgba;\n }\n\n clearCanvas(): void {\n if (this.canvas && this.ctx) {\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n }\n }\n\n destroy(): void {\n this.stopCamera();\n if (this.h264Decoder && this.h264Decoder.state !== 'closed') {\n try { this.h264Decoder.close(); } catch {}\n }\n this.h264Decoder = null;\n this.orientationMap.clear();\n this.canvas = null;\n this.ctx = null;\n }\n}\n\nfunction clamp(v: number): number {\n return v < 0 ? 0 : v > 255 ? 255 : v | 0;\n}\n","import type { CallInfo, CallState } from '../types';\n\nexport class CallStateManager {\n private calls = new Map<string, CallInfo>();\n\n addCall(call: CallInfo): void {\n this.calls.set(call.callId, { ...call });\n }\n\n updateState(callId: string, state: CallState): void {\n const call = this.calls.get(callId);\n if (!call) return;\n call.state = state;\n if (state === 'ended') {\n this.calls.delete(callId);\n }\n }\n\n updateIsVideo(callId: string, isVideo: boolean): void {\n const call = this.calls.get(callId);\n if (call) {\n call.isVideo = isVideo;\n }\n }\n\n removeCall(callId: string): void {\n this.calls.delete(callId);\n }\n\n getCall(callId: string): CallInfo | undefined {\n return this.calls.get(callId);\n }\n\n getActiveCall(): CallInfo | undefined {\n for (const call of this.calls.values()) {\n if (call.state === 'accepted' || call.state === 'active') {\n return call;\n }\n }\n return undefined;\n }\n\n getRingingCalls(): CallInfo[] {\n const result: CallInfo[] = [];\n for (const call of this.calls.values()) {\n if (call.state === 'ringing' || call.state === 'preaccepted') {\n result.push(call);\n }\n }\n return result;\n }\n\n getAllCalls(): CallInfo[] {\n return Array.from(this.calls.values());\n }\n\n hasActiveCalls(): boolean {\n for (const call of this.calls.values()) {\n if (call.state !== 'ended') return true;\n }\n return false;\n }\n\n clear(): void {\n this.calls.clear();\n }\n}\n","import type { ZAPICallTheme } from '../types';\n\nexport function buildCSS(theme: ZAPICallTheme): string {\n const light = theme.mode === 'light';\n\n const primary = theme.primaryColor || '#00a884';\n const danger = theme.dangerColor || '#f44336';\n const bg = theme.backgroundColor || (light ? '#f0f2f5' : '#202c33');\n const surface = theme.surfaceColor || (light ? '#ffffff' : '#111b21');\n const text = theme.textColor || (light ? '#111b21' : '#e9edef');\n const textSec = theme.textSecondaryColor || (light ? '#667781' : '#8696a0');\n const radius = theme.borderRadius || '16px';\n const font = theme.fontFamily || \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\";\n\n // Theme-aware overlays and shadows\n const overlay = light ? 'rgba(0,0,0,0.06)' : 'rgba(255,255,255,0.08)';\n const overlayHover = light ? 'rgba(0,0,0,0.1)' : 'rgba(255,255,255,0.1)';\n const overlayActive = light ? 'rgba(0,0,0,0.14)' : 'rgba(255,255,255,0.15)';\n const shadow = light ? 'rgba(0,0,0,0.12)' : 'rgba(0,0,0,0.3)';\n const shadowLg = light ? 'rgba(0,0,0,0.16)' : 'rgba(0,0,0,0.4)';\n const border = light ? 'rgba(0,0,0,0.08)' : 'rgba(255,255,255,0.06)';\n const borderLight = light ? 'rgba(0,0,0,0.12)' : 'rgba(255,255,255,0.1)';\n\n return `\n :host {\n all: initial;\n font-family: ${font};\n color: ${text};\n --primary: ${primary};\n --danger: ${danger};\n --bg: ${bg};\n --surface: ${surface};\n --text: ${text};\n --text-sec: ${textSec};\n --radius: ${radius};\n }\n\n * { margin: 0; padding: 0; box-sizing: border-box; }\n\n .zapi-call-root {\n position: fixed;\n z-index: 2147483647;\n font-family: ${font};\n }\n .zapi-call-root.bottom-right { bottom: 20px; right: 20px; }\n .zapi-call-root.bottom-left { bottom: 20px; left: 20px; }\n .zapi-call-root.top-right { top: 20px; right: 20px; }\n .zapi-call-root.top-left { top: 20px; left: 20px; }\n\n /* Bubble */\n .bubble {\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: var(--primary);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 4px 12px ${shadow};\n transition: transform 0.2s, box-shadow 0.2s;\n position: relative;\n user-select: none;\n }\n .bubble:hover { transform: scale(1.08); box-shadow: 0 6px 20px ${shadowLg}; }\n .bubble:active { transform: scale(0.95); }\n .bubble svg { width: 26px; height: 26px; color: #fff; }\n\n .bubble .badge {\n position: absolute;\n top: -2px;\n right: -2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--danger);\n color: #fff;\n font-size: 11px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n display: none;\n }\n .bubble .badge.visible { display: flex; }\n\n .bubble .conn-dot {\n position: absolute;\n bottom: 2px;\n right: 2px;\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: #f44336;\n border: 2px solid var(--primary);\n }\n .bubble .conn-dot.connected { background: #4caf50; }\n\n .bubble.ringing {\n animation: bubble-pulse 1.5s ease-in-out infinite;\n }\n @keyframes bubble-pulse {\n 0%, 100% { box-shadow: 0 4px 12px ${shadow}; }\n 50% { box-shadow: 0 4px 12px ${shadow}, 0 0 0 12px rgba(0,168,132,0.2); }\n }\n\n /* Panel */\n .panel {\n position: absolute;\n bottom: 66px;\n right: 0;\n width: 360px;\n max-height: 560px;\n background: var(--surface);\n border-radius: var(--radius);\n box-shadow: 0 8px 32px ${shadowLg};\n overflow: hidden;\n transform: translateY(10px);\n opacity: 0;\n pointer-events: none;\n transition: transform 0.25s ease, opacity 0.25s ease;\n display: flex;\n flex-direction: column;\n }\n .panel.open {\n transform: translateY(0);\n opacity: 1;\n pointer-events: auto;\n }\n .zapi-call-root.bottom-left .panel { right: auto; left: 0; }\n .zapi-call-root.top-right .panel { bottom: auto; top: 66px; }\n .zapi-call-root.top-left .panel { bottom: auto; top: 66px; right: auto; left: 0; }\n\n /* Panel header with tabs */\n .panel-header {\n background: var(--bg);\n border-bottom: 1px solid ${border};\n flex-shrink: 0;\n }\n .panel-header-top {\n padding: 10px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n .panel-header-top h3 {\n font-size: 15px;\n font-weight: 600;\n color: var(--text);\n }\n .panel-header .close-btn {\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: var(--text-sec);\n cursor: pointer;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s;\n }\n .panel-header .close-btn:hover { background: ${overlay}; }\n .panel-header .close-btn svg { width: 18px; height: 18px; }\n\n /* Tabs */\n .tabs {\n display: flex;\n padding: 0 8px;\n }\n .tab {\n flex: 1;\n padding: 10px 8px;\n border: none;\n background: transparent;\n color: var(--text-sec);\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: color 0.2s;\n font-family: inherit;\n }\n .tab svg { width: 16px; height: 16px; }\n .tab:hover { color: var(--text); }\n .tab.active { color: var(--primary); }\n .tab.active::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 16px;\n right: 16px;\n height: 2px;\n background: var(--primary);\n border-radius: 2px 2px 0 0;\n }\n\n /* Panel body / views */\n .panel-body {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n min-height: 0;\n }\n .view {\n display: none;\n animation: view-in 0.2s ease;\n }\n .view.active { display: block; }\n @keyframes view-in {\n from { opacity: 0; transform: translateY(6px); }\n to { opacity: 1; transform: translateY(0); }\n }\n\n /* ── Dialer view ── */\n .dialer {\n padding: 8px 16px 14px;\n display: flex;\n flex-direction: column;\n align-items: center;\n }\n .dialer-display {\n width: 100%;\n height: 56px;\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n margin-bottom: 8px;\n }\n .dialer-input {\n width: 100%;\n background: transparent;\n border: none;\n padding: 0 40px;\n color: var(--text);\n font-size: 28px;\n font-weight: 300;\n font-family: inherit;\n text-align: center;\n letter-spacing: 1.5px;\n outline: none;\n font-variant-numeric: tabular-nums;\n caret-color: var(--primary);\n }\n .dialer-input::placeholder { color: var(--text-sec); font-size: 16px; font-weight: 400; letter-spacing: 0; }\n .dialer-input.error::placeholder { color: #e74c3c; }\n .backspace-btn {\n position: absolute;\n right: 0;\n width: 36px;\n height: 36px;\n border: none;\n background: transparent;\n color: var(--text-sec);\n cursor: pointer;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s, color 0.2s;\n }\n .backspace-btn:hover { background: ${overlay}; color: var(--text); }\n .backspace-btn svg { width: 20px; height: 20px; }\n\n /* Numpad */\n .numpad {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 6px;\n width: 100%;\n max-width: 240px;\n margin-bottom: 12px;\n }\n .numpad-key {\n width: 60px;\n height: 60px;\n border-radius: 50%;\n border: none;\n background: var(--bg);\n color: var(--text);\n font-size: 22px;\n font-weight: 400;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n transition: background 0.15s, transform 0.1s;\n user-select: none;\n font-family: inherit;\n justify-self: center;\n line-height: 1;\n }\n .numpad-key:hover { background: ${overlayHover}; }\n .numpad-key:active { transform: scale(0.92); background: ${overlayActive}; }\n .numpad-key .sub {\n font-size: 8px;\n color: var(--text-sec);\n letter-spacing: 1.5px;\n margin-top: 1px;\n font-weight: 600;\n }\n\n /* Call buttons */\n .call-btns {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n .call-btn {\n width: 56px;\n height: 56px;\n border-radius: 50%;\n border: none;\n background: var(--primary);\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 16px rgba(0,168,132,0.3);\n transition: transform 0.15s, box-shadow 0.15s;\n }\n .call-btn:hover { transform: scale(1.08); box-shadow: 0 6px 24px rgba(0,168,132,0.4); }\n .call-btn:active { transform: scale(0.95); }\n .call-btn svg { width: 26px; height: 26px; }\n .call-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n box-shadow: 0 4px 16px rgba(0,168,132,0.15);\n }\n .video-call-btn {\n background: #2196f3;\n box-shadow: 0 4px 16px rgba(33,150,243,0.3);\n }\n .video-call-btn:hover { box-shadow: 0 6px 24px rgba(33,150,243,0.4); }\n\n /* ── Calls view ── */\n .calls-view {\n padding: 8px;\n }\n\n .empty-state {\n padding: 40px 16px;\n text-align: center;\n color: var(--text-sec);\n font-size: 13px;\n }\n .empty-state .icon {\n font-size: 36px;\n margin-bottom: 8px;\n }\n\n /* Call Card */\n .call-card {\n background: var(--bg);\n border-radius: 12px;\n padding: 14px;\n margin-bottom: 8px;\n animation: card-in 0.3s ease;\n }\n .call-card.ended {\n opacity: 0.5;\n animation: card-out 0.5s ease forwards;\n }\n @keyframes card-in {\n from { transform: translateY(-8px); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n @keyframes card-out {\n to { transform: translateY(8px); opacity: 0; }\n }\n\n .call-card-top {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 10px;\n }\n\n .avatar {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n background: var(--surface);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n }\n .avatar svg { width: 22px; height: 22px; color: var(--text-sec); }\n .avatar .avatar-img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }\n\n .call-info { flex: 1; min-width: 0; }\n .call-phone {\n font-size: 15px;\n font-weight: 600;\n color: var(--text);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .call-meta {\n font-size: 12px;\n color: var(--text-sec);\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 2px;\n }\n .call-meta svg { width: 13px; height: 13px; }\n\n .state-badge {\n padding: 3px 8px;\n border-radius: 6px;\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n flex-shrink: 0;\n }\n .state-badge.ringing {\n background: #f9a825;\n color: #000;\n animation: badge-pulse 1.5s ease-in-out infinite;\n }\n .state-badge.preaccepted { background: #ff9800; color: #000; }\n .state-badge.accepted { background: #2196f3; color: #fff; }\n .state-badge.active { background: var(--primary); color: #fff; }\n .state-badge.ended { background: var(--danger); color: #fff; }\n @keyframes badge-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n\n .timer {\n font-size: 22px;\n font-weight: 300;\n text-align: center;\n margin: 8px 0;\n font-variant-numeric: tabular-nums;\n color: var(--text);\n }\n\n .call-actions {\n display: flex;\n gap: 8px;\n margin-top: 8px;\n }\n\n .btn {\n flex: 1;\n padding: 10px 16px;\n border: none;\n border-radius: 24px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: transform 0.15s, opacity 0.15s;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n font-family: inherit;\n }\n .btn:hover { transform: scale(1.03); }\n .btn:active { transform: scale(0.97); }\n .btn svg { width: 18px; height: 18px; }\n .btn-accept { background: var(--primary); color: #fff; }\n .btn-reject { background: var(--danger); color: #fff; }\n .btn-mute {\n width: 44px;\n height: 44px;\n flex: none;\n border-radius: 50%;\n background: var(--bg);\n border: 1px solid ${borderLight};\n color: var(--text);\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: background 0.2s;\n }\n .btn-mute:hover { background: ${overlay}; }\n .btn-mute.muted { background: var(--danger); color: #fff; border-color: transparent; }\n .btn-mute svg { width: 20px; height: 20px; }\n\n /* ── In-Call view ── */\n .incall-view {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n }\n .incall-view .audio-call-ui {\n padding: 24px 16px;\n }\n .incall-avatar {\n width: 80px;\n height: 80px;\n border-radius: 50%;\n background: var(--bg);\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 16px;\n }\n .incall-avatar svg { width: 40px; height: 40px; color: var(--text-sec); }\n .incall-avatar .avatar-img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }\n .incall-phone {\n font-size: 20px;\n font-weight: 600;\n color: var(--text);\n margin-bottom: 4px;\n }\n .incall-state {\n font-size: 14px;\n color: var(--text-sec);\n margin-bottom: 4px;\n }\n .incall-timer {\n font-size: 28px;\n font-weight: 300;\n color: var(--text);\n font-variant-numeric: tabular-nums;\n margin-bottom: 20px;\n }\n\n /* Audio level bar */\n .audio-level-wrap {\n width: 100%;\n max-width: 200px;\n height: 6px;\n background: var(--bg);\n border-radius: 3px;\n overflow: hidden;\n margin-bottom: 28px;\n }\n .audio-level-bar {\n height: 100%;\n width: 0%;\n background: var(--primary);\n border-radius: 3px;\n transition: width 0.1s ease;\n }\n\n /* In-call controls */\n .incall-controls {\n display: flex;\n align-items: center;\n gap: 32px;\n }\n .incall-btn {\n width: 56px;\n height: 56px;\n border-radius: 50%;\n border: none;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: transform 0.15s;\n }\n .incall-btn:hover { transform: scale(1.08); }\n .incall-btn:active { transform: scale(0.95); }\n .incall-btn svg { width: 24px; height: 24px; }\n .incall-btn-mute {\n background: var(--bg);\n color: var(--text);\n border: 1px solid ${borderLight};\n }\n .incall-btn-mute.muted {\n background: var(--danger);\n color: #fff;\n border-color: transparent;\n }\n .incall-btn-camera {\n background: var(--bg);\n color: var(--text);\n border: 1px solid ${borderLight};\n }\n .incall-btn-camera:hover { background: ${overlay}; }\n .incall-btn-camera.muted {\n color: var(--text-sec);\n }\n .incall-btn-end {\n background: var(--danger);\n color: #fff;\n width: 64px;\n height: 64px;\n }\n .incall-btn-end svg { width: 28px; height: 28px; }\n\n /* ── Video Call ── */\n .audio-call-ui {\n display: flex;\n flex-direction: column;\n align-items: center;\n }\n .video-container {\n position: relative;\n width: 100%;\n height: 420px;\n overflow: hidden;\n background: #000;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 0 0 12px 12px;\n }\n .remote-video {\n max-width: 100%;\n max-height: 100%;\n display: block;\n object-fit: contain;\n }\n .video-overlay-top {\n position: absolute;\n top: 0; left: 0; right: 0;\n padding: 16px;\n background: linear-gradient(to bottom, rgba(0,0,0,0.6), transparent);\n z-index: 2;\n }\n .video-caller-info {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n .video-phone {\n font-size: 15px;\n font-weight: 600;\n color: #fff;\n text-shadow: 0 1px 3px rgba(0,0,0,0.5);\n }\n .video-timer {\n font-size: 14px;\n font-weight: 500;\n color: rgba(255,255,255,0.85);\n font-variant-numeric: tabular-nums;\n text-shadow: 0 1px 3px rgba(0,0,0,0.5);\n }\n .video-overlay-bottom {\n position: absolute;\n bottom: 0; left: 0; right: 0;\n padding: 20px;\n background: linear-gradient(to top, rgba(0,0,0,0.6), transparent);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 32px;\n z-index: 2;\n }\n .video-overlay-bottom .incall-btn {\n backdrop-filter: blur(8px);\n }\n .video-btn-mute {\n background: rgba(255,255,255,0.2) !important;\n color: #fff !important;\n border: none !important;\n }\n .video-btn-mute.muted {\n background: var(--danger) !important;\n }\n .video-btn-camera {\n background: rgba(255,255,255,0.2) !important;\n color: #fff !important;\n border: none !important;\n }\n .video-btn-camera.muted {\n background: rgba(255,255,255,0.1) !important;\n color: rgba(255,255,255,0.5) !important;\n }\n .video-btn-end {\n background: var(--danger) !important;\n color: #fff !important;\n }\n .video-btn-end svg { width: 28px; height: 28px; }\n\n /* ── Contacts view ── */\n .contacts-wrapper {\n display: flex;\n flex-direction: column;\n height: 400px;\n }\n .contacts-search-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n border-bottom: 1px solid ${border};\n flex-shrink: 0;\n }\n .contacts-search-input-wrap {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 8px;\n background: var(--bg);\n border-radius: 20px;\n padding: 0 12px;\n height: 36px;\n }\n .contacts-search-input-wrap svg {\n width: 16px;\n height: 16px;\n color: var(--text-sec);\n flex-shrink: 0;\n }\n .contacts-search-input {\n flex: 1;\n border: none;\n background: transparent;\n color: var(--text);\n font-size: 13px;\n font-family: inherit;\n outline: none;\n }\n .contacts-search-input::placeholder { color: var(--text-sec); }\n .contacts-refresh-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n color: var(--text-sec);\n cursor: pointer;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s, color 0.2s;\n flex-shrink: 0;\n }\n .contacts-refresh-btn:hover { background: ${overlay}; color: var(--text); }\n .contacts-refresh-btn svg { width: 18px; height: 18px; }\n\n .contacts-list {\n flex: 1;\n overflow-y: auto;\n padding: 4px 8px;\n }\n .contacts-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 16px;\n color: var(--text-sec);\n font-size: 13px;\n gap: 12px;\n }\n .spinner {\n width: 24px;\n height: 24px;\n border: 3px solid ${overlay};\n border-top-color: var(--primary);\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n @keyframes spin { to { transform: rotate(360deg); } }\n\n .contact-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 8px;\n border-radius: 10px;\n cursor: default;\n transition: background 0.15s;\n }\n .contact-item:hover { background: ${overlay}; }\n .contact-avatar {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: var(--bg);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n overflow: hidden;\n font-size: 14px;\n font-weight: 600;\n color: var(--text-sec);\n }\n .contact-avatar img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n .contact-info {\n flex: 1;\n min-width: 0;\n }\n .contact-name {\n font-size: 14px;\n font-weight: 500;\n color: var(--text);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .contact-phone {\n font-size: 12px;\n color: var(--text-sec);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .contact-call-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: var(--primary);\n color: #fff;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n flex-shrink: 0;\n transition: transform 0.15s;\n }\n .contact-call-btn:hover { transform: scale(1.1); }\n .contact-call-btn:active { transform: scale(0.95); }\n .contact-call-btn svg { width: 16px; height: 16px; }\n\n /* Hide header tabs during video call */\n .incall-view .video-container[style*=\"flex\"] ~ .panel-header { display: none; }\n `;\n}\n","export const ICON_PHONE = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M6.62 10.79a15.05 15.05 0 006.59 6.59l2.2-2.2a1 1 0 011.01-.24c1.12.37 2.33.57 3.57.57a1 1 0 011 1V20a1 1 0 01-1 1A17 17 0 013 4a1 1 0 011-1h3.5a1 1 0 011 1c0 1.25.2 2.45.57 3.57a1 1 0 01-.25 1.02l-2.2 2.2z\"/></svg>`;\n\nexport const ICON_PHONE_END = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 9c-1.6 0-3.15.25-4.6.72v3.1c0 .39-.23.74-.56.9-.98.49-1.87 1.12-2.66 1.85-.18.18-.43.28-.7.28-.28 0-.53-.11-.71-.29L.29 13.08a.956.956 0 010-1.36C3.34 8.75 7.46 7 12 7s8.66 1.75 11.71 4.72c.18.18.29.44.29.71 0 .28-.11.53-.29.71l-2.48 2.48c-.18.18-.43.29-.71.29-.27 0-.52-.11-.7-.28a11.27 11.27 0 00-2.67-1.85.99.99 0 01-.56-.9v-3.1C15.15 9.25 13.6 9 12 9z\"/></svg>`;\n\nexport const ICON_PHONE_ACCEPT = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M20.01 15.38c-1.23 0-2.42-.2-3.53-.56a.977.977 0 00-1.01.24l-1.57 1.97c-2.83-1.35-5.48-3.9-6.89-6.83l1.95-1.66c.27-.28.35-.67.24-1.02-.37-1.11-.56-2.3-.56-3.53 0-.54-.45-.99-.99-.99H4.19C3.65 3 3 3.24 3 3.99 3 13.28 10.73 21 20.01 21c.71 0 .99-.63.99-1.18v-3.45c0-.54-.45-.99-.99-.99z\"/></svg>`;\n\nexport const ICON_MIC = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm-1-9c0-.55.45-1 1-1s1 .45 1 1v6c0 .55-.45 1-1 1s-1-.45-1-1V5z\"/><path d=\"M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z\"/></svg>`;\n\nexport const ICON_MIC_OFF = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M19 11h-1.7c0 .74-.16 1.43-.43 2.05l1.23 1.23c.56-.98.9-2.09.9-3.28zm-4.02.17c0-.06.02-.11.02-.17V5c0-1.66-1.34-3-3-3S9 3.34 9 5v.18l5.98 5.99zM4.27 3L3 4.27l6.01 6.01V11c0 1.66 1.33 3 2.99 3 .22 0 .44-.03.65-.08l1.66 1.66c-.71.33-1.5.52-2.31.52-2.76 0-5.3-2.1-5.3-5.1H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c.91-.13 1.77-.45 2.54-.9L19.73 21 21 19.73 4.27 3z\"/></svg>`;\n\nexport const ICON_USER = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z\"/></svg>`;\n\nexport const ICON_VIDEO = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M17 10.5V7c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11l-4 4z\"/></svg>`;\n\nexport const ICON_VIDEO_OFF = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M21 6.5l-4 4V7c0-.55-.45-1-1-1H9.82L21 17.18V6.5zM3.27 2L2 3.27 4.73 6H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.21 0 .39-.08.54-.18L19.73 21 21 19.73 3.27 2z\"/></svg>`;\n\nexport const ICON_CLOSE = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z\"/></svg>`;\n\nexport const ICON_BACKSPACE = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59 12.59 12 9 8.41 10.41 7 14 10.59 17.59 7 19 8.41 15.41 12 19 15.59z\"/></svg>`;\n\nexport const ICON_DIALPAD = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 19c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zM6 1c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12-8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-6 8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z\"/></svg>`;\n\nexport const ICON_CALL_LIST = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M20 15.5c-1.25 0-2.45-.2-3.57-.57a1.02 1.02 0 00-1.02.24l-2.2 2.2a15.045 15.045 0 01-6.59-6.59l2.2-2.21a.96.96 0 00.25-1A11.36 11.36 0 018.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM19 12h2c0-4.97-4.03-9-9-9v2c3.87 0 7 3.13 7 7zm-4 0h2c0-2.76-2.24-5-5-5v2c1.66 0 3 1.34 3 3z\"/></svg>`;\n\nexport const ICON_CONTACTS = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5s-3 1.34-3 3 1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z\"/></svg>`;\n\nexport const ICON_SEARCH = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M15.5 14h-.79l-.28-.27a6.5 6.5 0 001.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 00-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 005.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z\"/></svg>`;\n\nexport const ICON_REFRESH = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M17.65 6.35A7.958 7.958 0 0012 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08A5.99 5.99 0 0112 18c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z\"/></svg>`;\n","/** Format millisecond duration as MM:SS */\nexport function formatDuration(ms: number): string {\n const totalSec = Math.floor(ms / 1000);\n const min = Math.floor(totalSec / 60);\n const sec = totalSec % 60;\n return `${String(min).padStart(2, '0')}:${String(sec).padStart(2, '0')}`;\n}\n\n/** Format phone number with country code for display */\nexport function formatPhone(phone: string): string {\n if (!phone || phone === 'unknown') return phone;\n // Strip non-digits\n const digits = phone.replace(/\\D/g, '');\n if (digits.length <= 4) return phone;\n // Brazilian format: +55 (XX) XXXXX-XXXX\n if (digits.length === 13 && digits.startsWith('55')) {\n return `+${digits.slice(0, 2)} (${digits.slice(2, 4)}) ${digits.slice(4, 9)}-${digits.slice(9)}`;\n }\n if (digits.length === 12 && digits.startsWith('55')) {\n return `+${digits.slice(0, 2)} (${digits.slice(2, 4)}) ${digits.slice(4, 8)}-${digits.slice(8)}`;\n }\n // Generic: +CC XXXXXXXX\n return `+${digits}`;\n}\n","import type { CallInfo, ContactInfo, ZAPICallTheme, WidgetPosition } from '../types';\nimport { buildCSS } from './CallWidget.css';\nimport {\n ICON_PHONE,\n ICON_PHONE_ACCEPT,\n ICON_PHONE_END,\n ICON_MIC,\n ICON_MIC_OFF,\n ICON_USER,\n ICON_VIDEO,\n ICON_VIDEO_OFF,\n ICON_CLOSE,\n ICON_BACKSPACE,\n ICON_DIALPAD,\n ICON_CALL_LIST,\n ICON_CONTACTS,\n ICON_SEARCH,\n ICON_REFRESH,\n} from './icons';\nimport { formatDuration, formatPhone } from '../utils/format';\n\ntype ViewName = 'dialer' | 'calls' | 'contacts' | 'incall';\n\nconst NUMPAD_KEYS: { digit: string; sub: string }[] = [\n { digit: '1', sub: '' },\n { digit: '2', sub: 'ABC' },\n { digit: '3', sub: 'DEF' },\n { digit: '4', sub: 'GHI' },\n { digit: '5', sub: 'JKL' },\n { digit: '6', sub: 'MNO' },\n { digit: '7', sub: 'PQRS' },\n { digit: '8', sub: 'TUV' },\n { digit: '9', sub: 'WXYZ' },\n { digit: '*', sub: '' },\n { digit: '0', sub: '+' },\n { digit: '#', sub: '' },\n];\n\nexport interface CallWidgetConfig {\n position: WidgetPosition;\n theme: ZAPICallTheme;\n showVideoDialButton: boolean;\n onAccept: (callId: string) => void;\n onReject: (callId: string) => void;\n onMute: (muted: boolean) => void;\n onCamera: (enabled: boolean) => void;\n onResume: () => void;\n onMakeCall: (number: string, isVideo: boolean) => void;\n onRequestContacts: () => void;\n onRequestProfilePicture: (phone: string) => void;\n}\n\nexport class CallWidget {\n private host: HTMLElement;\n private shadow: ShadowRoot;\n private root!: HTMLDivElement;\n private bubble!: HTMLDivElement;\n private badge!: HTMLSpanElement;\n private connDot!: HTMLSpanElement;\n private panel!: HTMLDivElement;\n private config: CallWidgetConfig;\n private open = false;\n private muted = false;\n private timers = new Map<string, ReturnType<typeof setInterval>>();\n private timerStarts = new Map<string, number>();\n\n // Views\n private currentView: ViewName = 'dialer';\n private dialerView!: HTMLDivElement;\n private callsView!: HTMLDivElement;\n private contactsView!: HTMLDivElement;\n private incallView!: HTMLDivElement;\n private dialerInput!: HTMLInputElement;\n private tabDialer!: HTMLButtonElement;\n private tabCalls!: HTMLButtonElement;\n private tabContacts!: HTMLButtonElement;\n private contactsLoaded = false;\n private contactsCache: ContactInfo[] = [];\n private pictureCache = new Map<string, string | null>();\n private pictureRequested = new Set<string>();\n\n // In-call state\n private incallTimerEl!: HTMLElement;\n private incallPhoneEl!: HTMLElement;\n private incallStateEl!: HTMLElement;\n private incallMuteBtn!: HTMLButtonElement;\n private audioLevelBar!: HTMLElement;\n private activeCallId: string | null = null;\n private cameraOn = false;\n\n // Video elements\n private remoteVideoCanvas!: HTMLCanvasElement;\n private videoContainer!: HTMLDivElement;\n private videoPhoneEl!: HTMLElement;\n private videoTimerEl!: HTMLElement;\n\n constructor(config: CallWidgetConfig) {\n this.config = config;\n\n this.host = document.createElement('div');\n this.host.id = 'zapi-call-widget';\n this.shadow = this.host.attachShadow({ mode: 'closed' });\n\n const style = document.createElement('style');\n style.textContent = buildCSS(config.theme);\n this.shadow.appendChild(style);\n\n this.buildDOM();\n document.body.appendChild(this.host);\n }\n\n private buildDOM(): void {\n this.root = document.createElement('div');\n this.root.className = `zapi-call-root ${this.config.position}`;\n\n // Panel\n this.panel = document.createElement('div');\n this.panel.className = 'panel';\n\n // Header with tabs\n const header = document.createElement('div');\n header.className = 'panel-header';\n header.innerHTML = `\n <div class=\"panel-header-top\">\n <h3>Telefone</h3>\n <button class=\"close-btn\">${ICON_CLOSE}</button>\n </div>\n <div class=\"tabs\">\n <button class=\"tab active\" data-tab=\"dialer\">${ICON_DIALPAD} Discador</button>\n <button class=\"tab\" data-tab=\"calls\">${ICON_CALL_LIST} Chamadas</button>\n <button class=\"tab\" data-tab=\"contacts\">${ICON_CONTACTS} Contatos</button>\n </div>\n `;\n header.querySelector('.close-btn')!.addEventListener('click', () => this.togglePanel(false));\n\n this.tabDialer = header.querySelector('[data-tab=\"dialer\"]')!;\n this.tabCalls = header.querySelector('[data-tab=\"calls\"]')!;\n this.tabContacts = header.querySelector('[data-tab=\"contacts\"]')!;\n this.tabDialer.addEventListener('click', () => this.switchView('dialer'));\n this.tabCalls.addEventListener('click', () => this.switchView('calls'));\n this.tabContacts.addEventListener('click', () => this.switchView('contacts'));\n\n this.panel.appendChild(header);\n\n // Panel body\n const body = document.createElement('div');\n body.className = 'panel-body';\n\n // Dialer view\n this.dialerView = document.createElement('div');\n this.dialerView.className = 'view active';\n this.buildDialerView();\n body.appendChild(this.dialerView);\n\n // Calls view\n this.callsView = document.createElement('div');\n this.callsView.className = 'view';\n this.callsView.innerHTML = `\n <div class=\"calls-view\">\n <div class=\"empty-state\">\n <div class=\"icon\">&#128222;</div>\n <p>Nenhuma chamada ativa</p>\n </div>\n </div>\n `;\n body.appendChild(this.callsView);\n\n // Contacts view\n this.contactsView = document.createElement('div');\n this.contactsView.className = 'view';\n this.buildContactsView();\n body.appendChild(this.contactsView);\n\n // In-call view\n this.incallView = document.createElement('div');\n this.incallView.className = 'view';\n this.buildInCallView();\n body.appendChild(this.incallView);\n\n this.panel.appendChild(body);\n this.root.appendChild(this.panel);\n\n // Bubble\n this.bubble = document.createElement('div');\n this.bubble.className = 'bubble';\n this.bubble.innerHTML = `\n ${ICON_PHONE}\n <span class=\"badge\">0</span>\n <span class=\"conn-dot\"></span>\n `;\n this.badge = this.bubble.querySelector('.badge')!;\n this.connDot = this.bubble.querySelector('.conn-dot')!;\n this.bubble.addEventListener('click', () => {\n this.togglePanel();\n this.config.onResume();\n });\n this.root.appendChild(this.bubble);\n\n this.shadow.appendChild(this.root);\n }\n\n private buildDialerView(): void {\n const dialer = document.createElement('div');\n dialer.className = 'dialer';\n\n // Number display\n const display = document.createElement('div');\n display.className = 'dialer-display';\n\n this.dialerInput = document.createElement('input');\n this.dialerInput.className = 'dialer-input';\n this.dialerInput.type = 'tel';\n this.dialerInput.placeholder = 'Digite o numero';\n this.dialerInput.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') this.handleMakeCall();\n });\n\n const backspaceBtn = document.createElement('button');\n backspaceBtn.className = 'backspace-btn';\n backspaceBtn.innerHTML = ICON_BACKSPACE;\n backspaceBtn.addEventListener('click', () => {\n this.dialerInput.value = this.dialerInput.value.slice(0, -1);\n this.dialerInput.focus();\n });\n\n display.appendChild(this.dialerInput);\n display.appendChild(backspaceBtn);\n dialer.appendChild(display);\n\n // Numpad\n const numpad = document.createElement('div');\n numpad.className = 'numpad';\n\n for (const key of NUMPAD_KEYS) {\n const btn = document.createElement('button');\n btn.className = 'numpad-key';\n btn.innerHTML = `<span>${key.digit}</span>${key.sub ? `<span class=\"sub\">${key.sub}</span>` : ''}`;\n btn.addEventListener('click', () => {\n this.dialerInput.value += key.digit;\n this.dialerInput.focus();\n });\n numpad.appendChild(btn);\n }\n\n dialer.appendChild(numpad);\n\n // Call buttons\n const callBtns = document.createElement('div');\n callBtns.className = 'call-btns';\n\n const callBtn = document.createElement('button');\n callBtn.className = 'call-btn';\n callBtn.innerHTML = ICON_PHONE;\n callBtn.addEventListener('click', () => this.handleMakeCall(false));\n callBtns.appendChild(callBtn);\n\n if (this.config.showVideoDialButton) {\n const videoCallBtn = document.createElement('button');\n videoCallBtn.className = 'call-btn video-call-btn';\n videoCallBtn.innerHTML = ICON_VIDEO;\n videoCallBtn.addEventListener('click', () => this.handleMakeCall(true));\n callBtns.appendChild(videoCallBtn);\n }\n\n dialer.appendChild(callBtns);\n\n this.dialerView.appendChild(dialer);\n }\n\n private buildContactsView(): void {\n const wrapper = document.createElement('div');\n wrapper.className = 'contacts-wrapper';\n\n const searchRow = document.createElement('div');\n searchRow.className = 'contacts-search-row';\n searchRow.innerHTML = `\n <div class=\"contacts-search-input-wrap\">\n ${ICON_SEARCH}\n <input class=\"contacts-search-input\" type=\"text\" placeholder=\"Buscar contato...\" />\n </div>\n <button class=\"contacts-refresh-btn\">${ICON_REFRESH}</button>\n `;\n\n const searchInput = searchRow.querySelector('.contacts-search-input') as HTMLInputElement;\n searchInput.addEventListener('input', () => this.filterContacts(searchInput.value));\n\n const refreshBtn = searchRow.querySelector('.contacts-refresh-btn')!;\n refreshBtn.addEventListener('click', () => {\n this.contactsLoaded = false;\n this.loadContacts();\n });\n\n wrapper.appendChild(searchRow);\n\n const list = document.createElement('div');\n list.className = 'contacts-list';\n list.innerHTML = `<div class=\"empty-state\"><p>Clique na aba para carregar</p></div>`;\n wrapper.appendChild(list);\n\n this.contactsView.appendChild(wrapper);\n }\n\n private loadContacts(): void {\n const list = this.contactsView.querySelector('.contacts-list')!;\n list.innerHTML = `<div class=\"contacts-loading\"><div class=\"spinner\"></div><p>Carregando contatos...</p></div>`;\n this.config.onRequestContacts();\n }\n\n private filterContacts(query: string): void {\n const q = query.toLowerCase().trim();\n const list = this.contactsView.querySelector('.contacts-list')!;\n const filtered = q ? this.contactsCache.filter(c =>\n c.name.toLowerCase().includes(q) || c.phone.includes(q)\n ) : this.contactsCache;\n this.renderContactsList(list, filtered);\n }\n\n private renderContactsList(container: Element, contacts: ContactInfo[]): void {\n if (contacts.length === 0) {\n container.innerHTML = `<div class=\"empty-state\"><p>Nenhum contato encontrado</p></div>`;\n return;\n }\n container.innerHTML = '';\n for (const contact of contacts) {\n const item = document.createElement('div');\n item.className = 'contact-item';\n const initials = (contact.short || contact.name || '?').charAt(0).toUpperCase();\n item.innerHTML = `\n <div class=\"contact-avatar\">${contact.imgUrl ? `<img src=\"${contact.imgUrl}\" />` : `<span>${initials}</span>`}</div>\n <div class=\"contact-info\">\n <div class=\"contact-name\">${contact.name || contact.phone}</div>\n <div class=\"contact-phone\">${contact.phone}</div>\n </div>\n <button class=\"contact-call-btn\">${ICON_PHONE}</button>\n `;\n item.querySelector('.contact-call-btn')!.addEventListener('click', () => {\n const phone = contact.phone.replace(/[^0-9+]/g, '');\n this.config.onMakeCall(phone, false);\n });\n container.appendChild(item);\n }\n }\n\n updateContacts(contacts: ContactInfo[]): void {\n this.contactsCache = contacts;\n this.contactsLoaded = true;\n const list = this.contactsView.querySelector('.contacts-list');\n if (list) this.renderContactsList(list, contacts);\n }\n\n private buildInCallView(): void {\n const view = document.createElement('div');\n view.className = 'incall-view';\n\n view.innerHTML = `\n <div class=\"video-container\" style=\"display:none;\">\n <canvas class=\"remote-video\"></canvas>\n <div class=\"video-overlay-top\">\n <div class=\"video-caller-info\">\n <div class=\"video-phone\"></div>\n <div class=\"video-timer\">00:00</div>\n </div>\n </div>\n <div class=\"video-overlay-bottom\">\n <button class=\"incall-btn video-btn-mute\">${ICON_MIC}</button>\n <button class=\"incall-btn video-btn-camera\">${ICON_VIDEO_OFF}</button>\n <button class=\"incall-btn video-btn-end\">${ICON_PHONE_END}</button>\n </div>\n </div>\n <div class=\"audio-call-ui\">\n <div class=\"incall-avatar\">${ICON_USER}</div>\n <div class=\"incall-phone\"></div>\n <div class=\"incall-state\"></div>\n <div class=\"incall-timer\">00:00</div>\n <div class=\"audio-level-wrap\">\n <div class=\"audio-level-bar\"></div>\n </div>\n <div class=\"incall-controls\">\n <button class=\"incall-btn incall-btn-mute\">${ICON_MIC}</button>\n <button class=\"incall-btn incall-btn-camera\">${ICON_VIDEO_OFF}</button>\n <button class=\"incall-btn incall-btn-end\">${ICON_PHONE_END}</button>\n </div>\n </div>\n `;\n\n this.videoContainer = view.querySelector('.video-container')!;\n this.remoteVideoCanvas = view.querySelector('.remote-video')!;\n\n this.incallPhoneEl = view.querySelector('.incall-phone')!;\n this.incallStateEl = view.querySelector('.incall-state')!;\n this.incallTimerEl = view.querySelector('.incall-timer')!;\n this.audioLevelBar = view.querySelector('.audio-level-bar')!;\n\n // Video overlay elements (duplicated info for video mode)\n this.videoPhoneEl = view.querySelector('.video-phone')!;\n this.videoTimerEl = view.querySelector('.video-timer')!;\n\n // Audio call mute button\n this.incallMuteBtn = view.querySelector('.incall-btn-mute')!;\n this.incallMuteBtn.addEventListener('click', () => {\n this.muted = !this.muted;\n this.config.onMute(this.muted);\n this.updateMuteButtons();\n });\n\n // Video call mute button\n const videoMuteBtn = view.querySelector('.video-btn-mute')!;\n videoMuteBtn.addEventListener('click', () => {\n this.muted = !this.muted;\n this.config.onMute(this.muted);\n this.updateMuteButtons();\n });\n\n // Camera toggle buttons (audio UI + video overlay)\n const cameraBtns = view.querySelectorAll('.video-btn-camera, .incall-btn-camera');\n cameraBtns.forEach(btn => {\n btn.addEventListener('click', () => {\n this.cameraOn = !this.cameraOn;\n this.config.onCamera(this.cameraOn);\n this.updateCameraButton();\n });\n });\n\n // End buttons (audio + video)\n const endBtn = view.querySelector('.incall-btn-end')!;\n endBtn.addEventListener('click', () => {\n if (this.activeCallId) this.config.onReject(this.activeCallId);\n });\n const videoEndBtn = view.querySelector('.video-btn-end')!;\n videoEndBtn.addEventListener('click', () => {\n if (this.activeCallId) this.config.onReject(this.activeCallId);\n });\n\n this.incallView.appendChild(view);\n }\n\n private handleMakeCall(isVideo = false): void {\n const number = this.dialerInput.value.replace(/\\s/g, '');\n if (!number) return;\n this.config.onMakeCall(number, isVideo);\n console.log('[ZAPICall] makeCall from widget:', number, isVideo ? '(video)' : '(audio)');\n }\n\n private switchView(view: ViewName): void {\n this.currentView = view;\n\n this.dialerView.classList.toggle('active', view === 'dialer');\n this.callsView.classList.toggle('active', view === 'calls');\n this.contactsView.classList.toggle('active', view === 'contacts');\n this.incallView.classList.toggle('active', view === 'incall');\n\n this.tabDialer.classList.toggle('active', view === 'dialer');\n this.tabCalls.classList.toggle('active', view === 'calls');\n this.tabContacts.classList.toggle('active', view === 'contacts');\n\n if (view === 'contacts' && !this.contactsLoaded) {\n this.loadContacts();\n }\n }\n\n private togglePanel(force?: boolean): void {\n this.open = force !== undefined ? force : !this.open;\n this.panel.classList.toggle('open', this.open);\n }\n\n updateCalls(calls: CallInfo[], connected: boolean): void {\n // Update connection dot\n this.connDot.classList.toggle('connected', connected);\n\n const activeCalls = calls.filter(c => c.state !== 'ended');\n const ringingCalls = calls.filter(c => c.state === 'ringing' || c.state === 'preaccepted' || c.state === 'calling');\n const liveCall = calls.find(c => c.state === 'active')\n || calls.find(c => c.state === 'accepted')\n || calls.find(c => c.state === 'calling');\n\n // Badge\n if (activeCalls.length > 0) {\n this.badge.textContent = String(activeCalls.length);\n this.badge.classList.add('visible');\n } else {\n this.badge.classList.remove('visible');\n }\n\n // Bubble pulse for ringing\n this.bubble.classList.toggle('ringing', ringingCalls.length > 0);\n\n // Auto-open panel on incoming call\n if (ringingCalls.length > 0 && !this.open) {\n this.togglePanel(true);\n }\n\n // Auto-switch to in-call view when a call becomes active\n if (liveCall) {\n this.activeCallId = liveCall.callId;\n this.incallPhoneEl.textContent = liveCall.notify || formatPhone(liveCall.from);\n this.incallStateEl.textContent = this.stateLabel(liveCall.state);\n if (this.videoPhoneEl) this.videoPhoneEl.textContent = liveCall.notify || formatPhone(liveCall.from);\n\n const incallAvatar = this.incallView.querySelector('.incall-avatar') as HTMLElement | null;\n if (incallAvatar && incallAvatar.dataset.avatarPhone !== liveCall.from) {\n incallAvatar.dataset.avatarPhone = liveCall.from;\n incallAvatar.innerHTML = this.renderAvatar(liveCall.from);\n }\n\n if (liveCall.state === 'accepted' || liveCall.state === 'active') {\n if (!this.timerStarts.has(liveCall.callId)) {\n this.timerStarts.set(liveCall.callId, Date.now());\n }\n this.startInCallTimer(liveCall.callId);\n } else {\n this.stopInCallTimer();\n }\n\n if (this.currentView !== 'incall') {\n this.switchView('incall');\n }\n } else if (this.currentView === 'incall') {\n // No more live calls, switch back\n this.activeCallId = null;\n this.stopInCallTimer();\n if (ringingCalls.length > 0) {\n this.switchView('calls');\n } else {\n this.switchView('dialer');\n }\n }\n\n // Auto-switch to calls when incoming and not in-call\n if (ringingCalls.length > 0 && !liveCall && this.currentView === 'dialer') {\n this.switchView('calls');\n }\n\n // Render calls list\n this.renderCallsList(calls);\n }\n\n private renderCallsList(calls: CallInfo[]): void {\n const container = this.callsView.querySelector('.calls-view')!;\n\n if (calls.length === 0) {\n container.innerHTML = `\n <div class=\"empty-state\">\n <div class=\"icon\">&#128222;</div>\n <p>Nenhuma chamada ativa</p>\n </div>\n `;\n this.clearAllTimers();\n return;\n }\n\n container.innerHTML = '';\n for (const call of calls) {\n container.appendChild(this.buildCallCard(call));\n }\n }\n\n private buildCallCard(call: CallInfo): HTMLDivElement {\n const card = document.createElement('div');\n card.className = `call-card${call.state === 'ended' ? ' ended' : ''}`;\n card.dataset.callId = call.callId;\n\n const isRinging = call.state === 'ringing' || call.state === 'preaccepted';\n const isCalling = call.state === 'calling';\n const isActive = call.state === 'accepted' || call.state === 'active';\n\n card.innerHTML = `\n <div class=\"call-card-top\">\n <div class=\"avatar\" data-avatar-phone=\"${call.from}\">${this.renderAvatar(call.from)}</div>\n <div class=\"call-info\">\n ${call.notify ? `<div class=\"call-name\">${call.notify}</div>` : ''}\n <div class=\"call-phone\">${formatPhone(call.from)}</div>\n <div class=\"call-meta\">\n ${call.isVideo ? ICON_VIDEO : ICON_PHONE}\n <span>${call.isVideo ? 'Video' : 'Audio'}${call.isGroup ? ' (Grupo)' : ''}</span>\n </div>\n </div>\n <span class=\"state-badge ${call.state}\">${this.stateLabel(call.state)}</span>\n </div>\n ${isActive ? `<div class=\"timer\" data-timer=\"${call.callId}\">00:00</div>` : ''}\n ${isRinging ? `\n <div class=\"call-actions\">\n <button class=\"btn btn-accept\" data-accept=\"${call.callId}\">\n ${ICON_PHONE_ACCEPT} Aceitar\n </button>\n <button class=\"btn btn-reject\" data-reject=\"${call.callId}\">\n ${ICON_PHONE_END} Rejeitar\n </button>\n </div>\n ` : ''}\n ${isCalling || isActive ? `\n <div class=\"call-actions\">\n <button class=\"btn btn-reject\" data-reject=\"${call.callId}\" style=\"flex:1\">\n ${ICON_PHONE_END} Encerrar\n </button>\n </div>\n ` : ''}\n `;\n\n // Wire button events\n const acceptBtn = card.querySelector(`[data-accept=\"${call.callId}\"]`);\n acceptBtn?.addEventListener('click', () => {\n this.config.onAccept(call.callId);\n this.config.onResume();\n });\n\n const rejectBtns = card.querySelectorAll(`[data-reject=\"${call.callId}\"]`);\n rejectBtns.forEach(btn => btn.addEventListener('click', () => this.config.onReject(call.callId)));\n\n // Start timer for active calls in list view\n if (isActive) {\n if (!this.timerStarts.has(call.callId)) {\n this.timerStarts.set(call.callId, Date.now());\n }\n this.startTimer(call.callId, card);\n }\n\n if (call.state === 'ended') {\n this.stopTimer(call.callId);\n }\n\n return card;\n }\n\n private stateLabel(state: string): string {\n switch (state) {\n case 'ringing': return 'Chamando';\n case 'calling': return 'Ligando...';\n case 'preaccepted': return 'Conectando';\n case 'accepted': return 'Aceita';\n case 'active': return 'Ativa';\n case 'ended': return 'Encerrada';\n default: return state;\n }\n }\n\n // Timers for call cards in list view\n private startTimer(callId: string, card: HTMLDivElement): void {\n this.stopTimer(callId);\n const startTime = this.timerStarts.get(callId) || Date.now();\n const el = card.querySelector(`[data-timer=\"${callId}\"]`) as HTMLElement | null;\n if (!el) return;\n\n const update = () => {\n el.textContent = formatDuration(Date.now() - startTime);\n };\n update();\n this.timers.set(callId, setInterval(update, 1000));\n }\n\n private stopTimer(callId: string): void {\n const timer = this.timers.get(callId);\n if (timer) {\n clearInterval(timer);\n this.timers.delete(callId);\n }\n }\n\n // In-call view timer\n private incallTimer: ReturnType<typeof setInterval> | null = null;\n\n private startInCallTimer(callId: string): void {\n this.stopInCallTimer();\n const startTime = this.timerStarts.get(callId) || Date.now();\n const update = () => {\n const text = formatDuration(Date.now() - startTime);\n this.incallTimerEl.textContent = text;\n if (this.videoTimerEl) this.videoTimerEl.textContent = text;\n };\n update();\n this.incallTimer = setInterval(update, 1000);\n }\n\n private stopInCallTimer(): void {\n if (this.incallTimer) {\n clearInterval(this.incallTimer);\n this.incallTimer = null;\n }\n this.incallTimerEl.textContent = '00:00';\n }\n\n /** Show video container for video calls */\n showVideo(isVideo: boolean): void {\n if (!this.videoContainer) return;\n this.videoContainer.style.display = isVideo ? 'flex' : 'none';\n const audioUi = this.incallView.querySelector('.audio-call-ui') as HTMLElement;\n if (audioUi) audioUi.style.display = isVideo ? 'none' : '';\n // Sync info to video overlay\n if (isVideo) {\n this.videoPhoneEl.textContent = this.incallPhoneEl.textContent;\n this.videoTimerEl.textContent = this.incallTimerEl.textContent;\n }\n }\n\n getRemoteCanvas(): HTMLCanvasElement { return this.remoteVideoCanvas; }\n\n resetCamera(): void {\n this.cameraOn = false;\n this.updateCameraButton();\n }\n\n private updateMuteButtons(): void {\n this.incallMuteBtn.classList.toggle('muted', this.muted);\n this.incallMuteBtn.innerHTML = this.muted ? ICON_MIC_OFF : ICON_MIC;\n const vmb = this.incallView.querySelector('.video-btn-mute') as HTMLElement;\n if (vmb) {\n vmb.classList.toggle('muted', this.muted);\n vmb.innerHTML = this.muted ? ICON_MIC_OFF : ICON_MIC;\n }\n }\n\n private updateCameraButton(): void {\n const btns = this.incallView.querySelectorAll('.video-btn-camera, .incall-btn-camera');\n btns.forEach(btn => {\n btn.classList.toggle('muted', !this.cameraOn);\n btn.innerHTML = this.cameraOn ? ICON_VIDEO : ICON_VIDEO_OFF;\n });\n }\n\n showMakeCallError(reason: string): void {\n const msg = reason.includes('PHONE_NOT_ON_WHATSAPP')\n ? 'N\\u00famero n\\u00e3o encontrado'\n : 'Erro ao realizar chamada';\n const prev = this.dialerInput.placeholder;\n this.dialerInput.value = '';\n this.dialerInput.placeholder = msg;\n this.dialerInput.classList.add('error');\n setTimeout(() => {\n this.dialerInput.placeholder = prev;\n this.dialerInput.classList.remove('error');\n }, 3000);\n }\n\n updateAudioLevel(level: number): void {\n const pct = Math.min(100, Math.max(0, level * 100));\n this.audioLevelBar.style.width = `${pct}%`;\n }\n\n private renderAvatar(phone: string): string {\n const cached = this.pictureCache.get(phone);\n if (cached) return `<img src=\"${cached}\" class=\"avatar-img\" />`;\n if (!this.pictureRequested.has(phone) && phone) {\n this.pictureRequested.add(phone);\n this.config.onRequestProfilePicture(phone);\n }\n return ICON_USER;\n }\n\n updateProfilePicture(phone: string, url: string | null): void {\n this.pictureCache.set(phone, url);\n if (!url) return;\n\n const avatarHtml = `<img src=\"${url}\" class=\"avatar-img\" />`;\n this.shadow.querySelectorAll(`[data-avatar-phone=\"${phone}\"]`).forEach((el) => {\n el.innerHTML = avatarHtml;\n });\n }\n\n private clearAllTimers(): void {\n for (const timer of this.timers.values()) {\n clearInterval(timer);\n }\n this.timers.clear();\n this.timerStarts.clear();\n this.stopInCallTimer();\n }\n\n destroy(): void {\n this.clearAllTimers();\n this.host.remove();\n }\n}\n","import type {\n ZAPICallOptions,\n ZAPICallEvents,\n CallInfo,\n ContactInfo,\n WsServerMessage,\n AudioConfig,\n VideoFrameInfo,\n} from '../types';\nimport { EventEmitter } from './EventEmitter';\nimport { CallWebSocket } from './CallWebSocket';\nimport { AudioEngine } from './AudioEngine';\nimport { VideoEngine } from './VideoEngine';\nimport { CallStateManager } from './CallState';\nimport { CallWidget } from '../widget/CallWidget';\n\nexport class ZAPICallClient extends EventEmitter<ZAPICallEvents> {\n private ws: CallWebSocket;\n private audio: AudioEngine;\n private video: VideoEngine;\n private state: CallStateManager;\n private widget: CallWidget | null = null;\n private opts: ZAPICallOptions;\n private audioConfig: AudioConfig = { sampleRate: 16000, channels: 1 };\n private connected = false;\n private micStarted = false;\n private cameraStarted = false;\n private destroyed = false;\n private sdkId = '';\n private contacts: ContactInfo[] = [];\n\n constructor(opts: ZAPICallOptions) {\n super();\n this.opts = opts;\n\n this.state = new CallStateManager();\n this.audio = new AudioEngine(this.audioConfig.sampleRate);\n this.video = new VideoEngine();\n this.ws = new CallWebSocket(__BASE_URL__, opts.instanceId, opts.getToken);\n\n // Wire WS events\n this.ws.onJson = (msg) => this.handleJsonMessage(msg);\n this.ws.onBinary = (data) => this.handleBinaryMessage(data);\n this.ws.onConnectionChange = (c) => this.handleConnectionChange(c);\n\n // Wire audio mic → WS\n this.audio.onMicData = (pcm) => {\n const framed = new ArrayBuffer(1 + pcm.byteLength);\n new Uint8Array(framed)[0] = 0x01;\n new Uint8Array(framed, 1).set(new Uint8Array(pcm));\n this.ws.send(framed);\n };\n this.audio.onAudioLevel = (level) => {\n this.emit('audio:level', level);\n this.widget?.updateAudioLevel(level);\n };\n\n // Wire video rendering\n this.on('video:frame', (frame) => this.video.renderFrame(frame));\n\n this.video.onEncodedCameraFrame = (h264, w, h, tsSec, isKey, latencyMs) => {\n const packet = new ArrayBuffer(22 + h264.byteLength);\n const view = new DataView(packet);\n view.setUint8(0, 0x03);\n view.setUint16(1, w, true);\n view.setUint16(3, h, true);\n view.setFloat64(5, tsSec);\n view.setUint8(13, isKey ? 1 : 0);\n view.setFloat64(14, latencyMs);\n new Uint8Array(packet, 22).set(new Uint8Array(h264));\n this.ws.send(packet);\n };\n\n this.video.onCameraFrame = (rgba, w, h) => {\n const nv12 = this.rgbaToNv12(new Uint8Array(rgba), w, h);\n const packet = new ArrayBuffer(5 + nv12.byteLength);\n const view = new DataView(packet);\n view.setUint8(0, 0x02);\n view.setUint16(1, w, true);\n view.setUint16(3, h, true);\n new Uint8Array(packet, 5).set(nv12);\n this.ws.send(packet);\n };\n\n // Create widget if enabled\n if (opts.autoWidget !== false) {\n this.widget = new CallWidget({\n position: opts.position || 'bottom-right',\n theme: opts.theme || {},\n showVideoDialButton: opts.showVideoDialButton === true,\n onAccept: (callId) => this.accept(callId),\n onReject: (callId) => this.reject(callId),\n onMute: (muted) => this.mute(muted),\n onCamera: (enabled) => this.setCamera(enabled),\n onResume: () => this.audio.resume(),\n onMakeCall: (number, isVideo) => this.makeCall(number, isVideo),\n onRequestContacts: () => this.requestContacts(),\n onRequestProfilePicture: (phone: string) => this.requestProfilePicture(phone),\n });\n\n // Attach video engine to widget canvas\n this.video.setRemoteCanvas(this.widget.getRemoteCanvas());\n }\n\n this.ws.connect();\n }\n\n // -- Public API --\n\n accept(callId: string): void {\n console.log('[ZAPICall] >> call:accept', callId);\n this.ws.sendJson({ type: 'call:accept', callId });\n this.startMicIfNeeded();\n }\n\n reject(callId: string): void {\n console.log('[ZAPICall] >> call:reject', callId);\n this.ws.sendJson({ type: 'call:reject', callId });\n }\n\n mute(muted: boolean): void {\n this.ws.sendJson({ type: 'call:mute', muted });\n }\n\n async setCamera(enabled: boolean): Promise<void> {\n this.ws.sendJson({ type: 'call:camera', enabled });\n if (enabled) {\n await this.startCameraIfNeeded();\n this.widget?.showVideo(true);\n } else {\n this.video.stopCamera();\n this.cameraStarted = false;\n }\n }\n\n isCameraActive(): boolean {\n return this.cameraStarted;\n }\n\n makeCall(number: string, isVideo = false): void {\n console.log('[ZAPICall] >> call:make', number, isVideo ? '(video)' : '(audio)');\n this.audio.resume();\n this.ws.sendJson({ type: 'call:make', number, isVideo });\n this.emit('call:make', number);\n this.opts.onMakeCall?.(number);\n }\n\n getCalls(): CallInfo[] {\n return this.state.getAllCalls();\n }\n\n getActiveCall(): CallInfo | undefined {\n return this.state.getActiveCall();\n }\n\n isConnected(): boolean {\n return this.connected;\n }\n\n getSdkId(): string {\n return this.sdkId;\n }\n\n requestContacts(): void {\n this.ws.sendJson({ type: 'contacts:list' });\n }\n\n requestProfilePicture(phone: string): void {\n this.ws.sendJson({ type: 'profile:picture', phone });\n }\n\n getContacts(): ContactInfo[] {\n return this.contacts;\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.ws.destroy();\n this.audio.destroy();\n this.video.destroy();\n this.widget?.destroy();\n this.state.clear();\n this.removeAllListeners();\n }\n\n // -- Internal --\n\n private handleJsonMessage(msg: WsServerMessage): void {\n switch (msg.type) {\n case 'connected':\n this.sdkId = msg.sdkId || '';\n if (msg.audioConfig) {\n // Recreate audio engine if sample rate changed\n if (msg.audioConfig.sampleRate !== this.audioConfig.sampleRate) {\n this.audio.destroy();\n this.audio = new AudioEngine(msg.audioConfig.sampleRate);\n this.audio.onMicData = (pcm) => {\n const framed = new ArrayBuffer(1 + pcm.byteLength);\n new Uint8Array(framed)[0] = 0x01;\n new Uint8Array(framed, 1).set(new Uint8Array(pcm));\n this.ws.send(framed);\n };\n this.audio.onAudioLevel = (level) => {\n this.emit('audio:level', level);\n this.widget?.updateAudioLevel(level);\n };\n }\n this.audioConfig = msg.audioConfig;\n }\n break;\n\n case 'call:incoming': {\n const call: CallInfo = {\n callId: msg.callId,\n from: msg.from,\n notify: msg.notify,\n isVideo: msg.isVideo,\n isGroup: msg.isGroup,\n state: msg.state || 'ringing',\n timestamp: msg.timestamp,\n };\n this.state.addCall(call);\n this.emit('call:incoming', call);\n this.opts.onIncomingCall?.(call);\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n break;\n }\n\n case 'call:outgoing': {\n const outCall: CallInfo = {\n callId: msg.callId,\n from: msg.to,\n isVideo: msg.isVideo,\n isGroup: false,\n state: 'calling',\n timestamp: Date.now(),\n };\n this.state.addCall(outCall);\n this.emit('call:outgoing', outCall);\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n this.startMicIfNeeded();\n break;\n }\n\n case 'call:state': {\n if (!this.state.getCall(msg.callId)) break;\n this.state.updateState(msg.callId, msg.state);\n this.emit('call:state', msg.callId, msg.state);\n\n if (msg.state === 'accepted' || msg.state === 'active') {\n this.startMicIfNeeded();\n\n const call = this.state.getCall(msg.callId);\n if (call?.isVideo) {\n this.widget?.showVideo(true);\n this.startCameraIfNeeded();\n } else {\n this.video.stopCamera();\n this.cameraStarted = false;\n this.widget?.showVideo(false);\n }\n }\n\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n break;\n }\n\n case 'call:terminated': {\n this.state.updateState(msg.callId, 'ended');\n this.emit('call:terminated', msg.callId, msg.reason);\n this.opts.onCallTerminated?.(msg.callId);\n\n this.video.stopCamera();\n this.video.clearCanvas();\n this.cameraStarted = false;\n this.widget?.showVideo(false);\n this.widget?.resetCamera();\n\n setTimeout(() => {\n this.state.removeCall(msg.callId);\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n\n if (!this.state.hasActiveCalls()) {\n this.audio.stopMic();\n this.micStarted = false;\n }\n }, 3000);\n\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n break;\n }\n\n case 'call:video-state': {\n this.state.updateIsVideo(msg.callId, msg.isVideo);\n this.emit('call:video-state', msg.callId, msg.isVideo);\n\n const vCall = this.state.getCall(msg.callId);\n if (vCall && (vCall.state === 'accepted' || vCall.state === 'active')) {\n if (msg.isVideo) {\n this.widget?.showVideo(true);\n } else {\n this.video.stopCamera();\n this.cameraStarted = false;\n this.widget?.showVideo(false);\n }\n }\n\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n break;\n }\n\n case 'call:claimed': {\n this.state.removeCall(msg.callId);\n this.emit('call:claimed', msg.callId);\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n break;\n }\n\n case 'call:dismissed': {\n this.state.removeCall(msg.callId);\n this.emit('call:dismissed', msg.callId);\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n break;\n }\n\n case 'contacts:list': {\n this.contacts = msg.contacts || [];\n this.emit('contacts:list', this.contacts);\n this.widget?.updateContacts(this.contacts);\n break;\n }\n\n case 'profile:picture': {\n this.emit('profile:picture', msg.phone, msg.url);\n this.widget?.updateProfilePicture(msg.phone, msg.url);\n break;\n }\n\n case 'pong':\n break;\n\n case 'error':\n if (msg.command === 'call:make') {\n this.emit('call:make:error', '', msg.message || 'UNKNOWN_ERROR');\n this.widget?.showMakeCallError(msg.message || 'UNKNOWN_ERROR');\n }\n this.emit('error', new Error(`${msg.command}: ${msg.message}`));\n break;\n }\n }\n\n private handleBinaryMessage(data: ArrayBuffer): void {\n if (data.byteLength < 2) return;\n const view = new DataView(data);\n const firstByte = view.getUint8(0);\n\n // Video frame: prefix 0x01 + 15 bytes header + pixel data (always >= 16 bytes)\n if (firstByte === 0x01 && data.byteLength >= 16) {\n const width = view.getUint16(1, true);\n const height = view.getUint16(3, true);\n const format = view.getUint8(5);\n const orientation = view.getUint8(6);\n const isKeyFrame = view.getUint8(7) !== 0;\n const timestamp = view.getFloat64(8, false);\n const frameData = data.slice(16);\n\n const frame: VideoFrameInfo = {\n width, height, format, orientation,\n isKeyFrame, timestamp, data: frameData,\n };\n this.emit('video:frame', frame);\n return;\n }\n\n // Audio: prefix 0x00 + PCM data (odd total length since PCM is always even)\n if (firstByte === 0x00 && data.byteLength % 2 === 1) {\n this.audio.playPcm(data.slice(1));\n return;\n }\n\n // Legacy/fallback: raw PCM Int16LE (even length, no prefix)\n this.audio.playPcm(data);\n }\n\n private handleConnectionChange(connected: boolean): void {\n this.connected = connected;\n if (connected) {\n this.emit('connected');\n } else {\n this.emit('disconnected');\n }\n this.opts.onConnectionChange?.(connected);\n this.widget?.updateCalls(this.state.getAllCalls(), connected);\n }\n\n private async startCameraIfNeeded(): Promise<void> {\n if (this.cameraStarted || this.destroyed) return;\n this.cameraStarted = true;\n try {\n const videoEl = document.createElement('video');\n videoEl.style.display = 'none';\n document.body.appendChild(videoEl);\n await this.video.startCamera(videoEl, 320, 240, 30);\n } catch (e) {\n console.warn('[ZAPICall] Camera start failed:', e);\n this.cameraStarted = false;\n }\n }\n\n private rgbaToNv12(rgba: Uint8Array, w: number, h: number): Uint8Array {\n const ySize = w * h;\n const nv12 = new Uint8Array(ySize + (ySize >> 1));\n // Y plane\n for (let j = 0; j < h; j++) {\n for (let i = 0; i < w; i++) {\n const idx = (j * w + i) * 4;\n nv12[j * w + i] = ((66 * rgba[idx] + 129 * rgba[idx + 1] + 25 * rgba[idx + 2] + 128) >> 8) + 16;\n }\n }\n // UV plane (NV12 interleaved)\n let uvOff = ySize;\n for (let j = 0; j < h; j += 2) {\n for (let i = 0; i < w; i += 2) {\n const idx = (j * w + i) * 4;\n nv12[uvOff++] = ((-38 * rgba[idx] - 74 * rgba[idx + 1] + 112 * rgba[idx + 2] + 128) >> 8) + 128;\n nv12[uvOff++] = ((112 * rgba[idx] - 94 * rgba[idx + 1] - 18 * rgba[idx + 2] + 128) >> 8) + 128;\n }\n }\n return nv12;\n }\n\n private async startMicIfNeeded(): Promise<void> {\n if (this.micStarted || this.destroyed) return;\n this.micStarted = true;\n try {\n await this.audio.startMic();\n } catch (e) {\n this.emit('error', e instanceof Error ? e : new Error(String(e)));\n }\n }\n\n}\n","export type ThemeMode = 'dark' | 'light';\n\nexport interface ZAPICallTheme {\n mode?: ThemeMode;\n primaryColor?: string;\n dangerColor?: string;\n backgroundColor?: string;\n surfaceColor?: string;\n textColor?: string;\n textSecondaryColor?: string;\n borderRadius?: string;\n fontFamily?: string;\n}\n\nexport type WidgetPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n\nexport interface ZAPICallOptions {\n instanceId: string;\n getToken: () => Promise<string>;\n autoWidget?: boolean;\n showVideoDialButton?: boolean;\n position?: WidgetPosition;\n theme?: ZAPICallTheme;\n onIncomingCall?: (call: CallInfo) => void;\n onCallTerminated?: (callId: string) => void;\n onConnectionChange?: (connected: boolean) => void;\n onMakeCall?: (number: string) => void;\n}\n\nexport type CallState = 'ringing' | 'calling' | 'preaccepted' | 'accepted' | 'active' | 'ended';\n\nexport interface CallInfo {\n callId: string;\n from: string;\n notify?: string;\n isVideo: boolean;\n isGroup: boolean;\n state: CallState;\n timestamp: number;\n}\n\nexport interface AudioConfig {\n sampleRate: number;\n channels: number;\n}\n\nexport const VideoFormat = { NV12: 0, I420: 1, RGB24: 2, RGBA: 3, H264: 100 } as const;\nexport const VideoOrientation = { Unknown: 0, Normal: 1, Rotate90: 2, Rotate180: 3, Rotate270: 4 } as const;\n\nexport interface VideoFrameInfo {\n width: number;\n height: number;\n format: number;\n orientation: number;\n isKeyFrame: boolean;\n timestamp: number;\n data: ArrayBuffer;\n}\n\n// WebSocket protocol messages (server → client)\nexport interface WsConnectedMsg {\n type: 'connected';\n instanceId: string;\n sdkId: string;\n audioConfig: AudioConfig;\n}\n\nexport interface WsCallIncomingMsg {\n type: 'call:incoming';\n callId: string;\n from: string;\n notify?: string;\n isVideo: boolean;\n isGroup: boolean;\n state?: CallState;\n timestamp: number;\n}\n\nexport interface WsCallStateMsg {\n type: 'call:state';\n callId: string;\n state: CallState;\n}\n\nexport interface WsCallTerminatedMsg {\n type: 'call:terminated';\n callId: string;\n reason?: string;\n}\n\nexport interface WsPongMsg {\n type: 'pong';\n ts: number;\n}\n\nexport interface WsCallMakeMsg {\n type: 'call:make';\n number: string;\n}\n\nexport interface WsCallOutgoingMsg {\n type: 'call:outgoing';\n callId: string;\n to: string;\n isVideo: boolean;\n}\n\nexport interface WsErrorMsg {\n type: 'error';\n command: string;\n message: string;\n}\n\nexport interface WsCallClaimedMsg {\n type: 'call:claimed';\n callId: string;\n}\n\nexport interface WsCallDismissedMsg {\n type: 'call:dismissed';\n callId: string;\n}\n\nexport interface WsCallVideoStateMsg {\n type: 'call:video-state';\n callId: string;\n isVideo: boolean;\n}\n\nexport interface ContactInfo {\n name: string;\n phone: string;\n short: string;\n imgUrl: string | null;\n}\n\nexport interface WsContactsListMsg {\n type: 'contacts:list';\n contacts: ContactInfo[];\n}\n\nexport interface WsProfilePictureMsg {\n type: 'profile:picture';\n phone: string;\n url: string | null;\n}\n\nexport type WsServerMessage =\n | WsConnectedMsg\n | WsCallIncomingMsg\n | WsCallOutgoingMsg\n | WsCallStateMsg\n | WsCallTerminatedMsg\n | WsCallClaimedMsg\n | WsCallDismissedMsg\n | WsCallVideoStateMsg\n | WsContactsListMsg\n | WsProfilePictureMsg\n | WsPongMsg\n | WsErrorMsg;\n\n// Events emitted by ZAPICallClient\nexport interface ZAPICallEvents {\n 'connected': () => void;\n 'disconnected': () => void;\n 'call:incoming': (call: CallInfo) => void;\n 'call:state': (callId: string, state: CallState) => void;\n 'call:terminated': (callId: string, reason?: string) => void;\n 'call:claimed': (callId: string) => void;\n 'call:dismissed': (callId: string) => void;\n 'call:video-state': (callId: string, isVideo: boolean) => void;\n 'contacts:list': (contacts: ContactInfo[]) => void;\n 'call:make': (number: string) => void;\n 'call:outgoing': (call: CallInfo) => void;\n 'audio:level': (level: number) => void;\n 'video:frame': (frame: VideoFrameInfo) => void;\n 'call:make:error': (number: string, reason: string) => void;\n 'profile:picture': (phone: string, url: string | null) => void;\n 'error': (error: Error) => void;\n}\n","import { ZAPICallClient } from './core/ZAPICallClient';\nimport type { ZAPICallOptions } from './types';\n\n// Re-export types for TypeScript consumers\nexport type {\n ZAPICallOptions,\n ZAPICallTheme,\n ThemeMode,\n WidgetPosition,\n CallState,\n CallInfo,\n AudioConfig,\n VideoFrameInfo,\n ZAPICallEvents,\n WsCallMakeMsg,\n} from './types';\n\nexport { VideoFormat, VideoOrientation } from './types';\n\n// Re-export class for advanced usage\nexport { ZAPICallClient } from './core/ZAPICallClient';\n\n/**\n * Initialize the SDK. Creates a WebSocket connection, optional widget,\n * and returns a client for controlling calls.\n *\n * @example\n * ```ts\n * // ESM\n * import { init } from '@z-api/call';\n * const client = init({ instanceId: '123', getToken: async () => 'abc' });\n *\n * // or via namespace\n * import { ZAPICall } from '@z-api/call';\n * const client = ZAPICall.init({ instanceId: '123', getToken: async () => 'abc' });\n *\n * // Script tag\n * // <script src=\"z-api-call.global.js\"></script>\n * // const client = ZAPICall.init({ instanceId: '123', getToken: async () => 'abc' });\n * ```\n */\nexport function init(opts: ZAPICallOptions): ZAPICallClient {\n return new ZAPICallClient(opts);\n}\n\n/** Namespace object for convenience. */\nexport const ZAPICall = {\n init,\n Client: ZAPICallClient,\n};\n"],"names":["EventEmitter","event","listener","_a","args","set","e","INITIAL_RECONNECT_MS","MAX_RECONNECT_MS","PING_INTERVAL_MS","CallWebSocket","baseUrl","instanceId","getToken","token","u","url","ws","parsed","data","msg","int16ToFloat32","int16","float32","i","float32ToInt16","s","calculateRmsLevel","samples","sum","SCHEDULE_AHEAD_S","MAX_QUEUE_S","AudioEngine","sampleRate","int16Preview","maxVal","abs","level","buffer","source","now","track","H264_FORMAT","H264_CODEC","MAX_DECODER_ERRORS","VideoEngine","canvas","frame","width","height","orientation","format","isKeyFrame","timestamp","_width","_height","tsUs","decoder","vf","w","h","isRotated","displayW","displayH","nv12","rgba","imgData","videoEl","fps","stream","encodeW","encodeH","frameCount","submitTimes","chunk","meta","buf","isKey","codedW","codedH","_b","latencyMs","submitted","tsSec","reader","done","sinceLastKey","needKey","yPlaneSize","j","yIdx","uvIdx","y","v","rgbaIdx","clamp","CallStateManager","call","callId","state","isVideo","result","buildCSS","theme","light","primary","danger","bg","surface","text","textSec","radius","font","overlay","overlayHover","overlayActive","shadow","shadowLg","border","borderLight","ICON_PHONE","ICON_PHONE_END","ICON_PHONE_ACCEPT","ICON_MIC","ICON_MIC_OFF","ICON_USER","ICON_VIDEO","ICON_VIDEO_OFF","ICON_CLOSE","ICON_BACKSPACE","ICON_DIALPAD","ICON_CALL_LIST","ICON_CONTACTS","ICON_SEARCH","ICON_REFRESH","formatDuration","ms","totalSec","min","sec","formatPhone","phone","digits","NUMPAD_KEYS","CallWidget","config","style","header","body","dialer","display","backspaceBtn","numpad","key","btn","callBtns","callBtn","videoCallBtn","wrapper","searchRow","searchInput","list","query","q","filtered","c","container","contacts","contact","item","initials","view","number","force","calls","connected","activeCalls","ringingCalls","liveCall","incallAvatar","card","isRinging","isCalling","isActive","acceptBtn","startTime","el","update","timer","audioUi","vmb","reason","prev","pct","cached","avatarHtml","ZAPICallClient","opts","pcm","framed","h264","packet","muted","enabled","_c","outCall","_d","_e","_f","_g","_i","_h","_j","_k","_l","vCall","_m","_n","_o","_p","_q","_r","_s","_t","firstByte","frameData","ySize","idx","uvOff","VideoFormat","VideoOrientation","init","ZAPICall"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yCAwGjBA,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAgCVC,CAAY;AAAA,+DACaC,CAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAuLlDI,CAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oCASDN,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAsFjBM,CAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAUXA,CAAW;AAAA;AAAA,6CAEQN,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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"}
1
+ {"version":3,"file":"z-api-call.global.js","sources":["../src/core/EventEmitter.ts","../src/core/CallWebSocket.ts","../src/utils/pcm.ts","../src/core/AudioEngine.ts","../src/core/VideoEngine.ts","../src/core/CallState.ts","../src/widget/CallWidget.css.ts","../src/widget/icons.ts","../src/utils/format.ts","../src/widget/CallWidget.ts","../src/core/ZAPICallClient.ts","../src/types.ts","../src/index.ts"],"sourcesContent":["type Listener = (...args: any[]) => void;\n\nexport class EventEmitter<Events extends { [K in keyof Events]: Listener }> {\n private listeners = new Map<keyof Events, Set<Listener>>();\n\n on<K extends keyof Events>(event: K, listener: Events[K]): this {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener as Listener);\n return this;\n }\n\n off<K extends keyof Events>(event: K, listener: Events[K]): this {\n this.listeners.get(event)?.delete(listener as Listener);\n return this;\n }\n\n protected emit<K extends keyof Events>(event: K, ...args: Parameters<Events[K]>): void {\n const set = this.listeners.get(event);\n if (!set) return;\n for (const listener of set) {\n try {\n listener(...args);\n } catch (e) {\n console.error(`[ZAPICall] Event listener error (${String(event)}):`, e);\n }\n }\n }\n\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","import type { WsServerMessage } from '../types';\n\nexport type OnJsonMessage = (msg: WsServerMessage) => void;\nexport type OnBinaryMessage = (data: ArrayBuffer) => void;\nexport type OnConnectionChange = (connected: boolean) => void;\n\nconst INITIAL_RECONNECT_MS = 1000;\nconst MAX_RECONNECT_MS = 30000;\nconst PING_INTERVAL_MS = 25000;\n\nexport class CallWebSocket {\n private ws: WebSocket | null = null;\n private baseUrl: string;\n private instanceId: string;\n private getToken: () => Promise<string>;\n private reconnectMs = INITIAL_RECONNECT_MS;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private pingTimer: ReturnType<typeof setInterval> | null = null;\n private destroyed = false;\n\n onJson: OnJsonMessage = () => {};\n onBinary: OnBinaryMessage = () => {};\n onConnectionChange: OnConnectionChange = () => {};\n\n constructor(baseUrl: string, instanceId: string, getToken: () => Promise<string>) {\n this.baseUrl = baseUrl;\n this.instanceId = instanceId;\n this.getToken = getToken;\n }\n\n private buildUrl(token: string): string {\n const u = new URL(this.baseUrl);\n u.protocol = u.protocol === 'https:' ? 'wss:' : 'ws:';\n u.pathname = '/ws/call';\n u.searchParams.set('instance', this.instanceId);\n u.searchParams.set('token', token);\n return u.toString();\n }\n\n async connect(): Promise<void> {\n if (this.destroyed) return;\n this.cleanup();\n\n let token: string;\n try {\n token = await this.getToken();\n } catch (e) {\n console.warn('[ZAPICall] Failed to get token:', e);\n this.scheduleReconnect();\n return;\n }\n\n if (this.destroyed) return;\n\n const url = this.buildUrl(token);\n console.log('[ZAPICall] Connecting to', url);\n\n const ws = new WebSocket(url);\n ws.binaryType = 'arraybuffer';\n this.ws = ws;\n\n ws.onopen = () => {\n console.log('[ZAPICall] WebSocket connected');\n this.reconnectMs = INITIAL_RECONNECT_MS;\n this.onConnectionChange(true);\n this.startPing();\n };\n\n ws.onmessage = (event) => {\n if (typeof event.data === 'string') {\n try {\n const parsed = JSON.parse(event.data) as WsServerMessage;\n console.log('[ZAPICall] <<', parsed.type, parsed);\n this.onJson(parsed);\n } catch {}\n } else if (event.data instanceof ArrayBuffer) {\n this.onBinary(event.data);\n }\n };\n\n ws.onclose = (event) => {\n console.log('[ZAPICall] WebSocket closed:', event.code, event.reason);\n this.stopPing();\n this.onConnectionChange(false);\n if (event.code === 4001) {\n console.warn('[ZAPICall] Invalid credentials (4001), not reconnecting');\n return;\n }\n this.scheduleReconnect();\n };\n\n ws.onerror = (event) => {\n console.warn('[ZAPICall] WebSocket error:', event);\n };\n }\n\n send(data: string | ArrayBuffer): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.ws.send(data);\n }\n }\n\n sendJson(msg: Record<string, unknown>): void {\n this.send(JSON.stringify(msg));\n }\n\n isConnected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n destroy(): void {\n this.destroyed = true;\n this.cleanup();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n\n private cleanup(): void {\n this.stopPing();\n if (this.ws) {\n this.ws.onopen = null;\n this.ws.onmessage = null;\n this.ws.onclose = null;\n this.ws.onerror = null;\n if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.close();\n }\n this.ws = null;\n }\n }\n\n private scheduleReconnect(): void {\n if (this.destroyed) return;\n this.reconnectTimer = setTimeout(() => {\n this.connect();\n }, this.reconnectMs);\n this.reconnectMs = Math.min(this.reconnectMs * 2, MAX_RECONNECT_MS);\n }\n\n private startPing(): void {\n this.pingTimer = setInterval(() => {\n this.sendJson({ type: 'ping' });\n }, PING_INTERVAL_MS);\n }\n\n private stopPing(): void {\n if (this.pingTimer) {\n clearInterval(this.pingTimer);\n this.pingTimer = null;\n }\n }\n}\n","/** Convert Int16LE array to Float32 [-1, 1] for Web Audio playback */\nexport function int16ToFloat32(int16: Int16Array): Float32Array {\n const float32 = new Float32Array(int16.length);\n for (let i = 0; i < int16.length; i++) {\n float32[i] = int16[i] / 32768;\n }\n return float32;\n}\n\n/** Convert Float32 [-1, 1] to Int16LE for sending mic audio */\nexport function float32ToInt16(float32: Float32Array): Int16Array {\n const int16 = new Int16Array(float32.length);\n for (let i = 0; i < float32.length; i++) {\n let s = float32[i];\n if (s > 1) s = 1;\n else if (s < -1) s = -1;\n int16[i] = Math.round(s * 32767);\n }\n return int16;\n}\n\n/** Calculate RMS level (0-1) from Float32 samples */\nexport function calculateRmsLevel(samples: Float32Array): number {\n if (samples.length === 0) return 0;\n let sum = 0;\n for (let i = 0; i < samples.length; i++) {\n sum += samples[i] * samples[i];\n }\n return Math.sqrt(sum / samples.length);\n}\n","import { int16ToFloat32, float32ToInt16, calculateRmsLevel } from '../utils/pcm';\n\nconst SCHEDULE_AHEAD_S = 0.02;\nconst MAX_QUEUE_S = 0.15;\n\nexport type OnMicData = (pcmInt16: ArrayBuffer) => void;\nexport type OnAudioLevel = (level: number) => void;\n\nexport class AudioEngine {\n private playbackCtx: AudioContext | null = null;\n private micCtx: AudioContext | null = null;\n private micStream: MediaStream | null = null;\n private micProcessor: ScriptProcessorNode | null = null;\n private micSource: MediaStreamAudioSourceNode | null = null;\n private nextPlayTime = 0;\n private sampleRate: number;\n private destroyed = false;\n\n onMicData: OnMicData = () => {};\n onAudioLevel: OnAudioLevel = () => {};\n\n constructor(sampleRate = 48000) {\n this.sampleRate = sampleRate;\n }\n\n /** Play received PCM Int16LE audio */\n private playLogCount = 0;\n\n playPcm(data: ArrayBuffer): void {\n if (this.destroyed || data.byteLength === 0) return;\n\n if (!this.playbackCtx) {\n this.playbackCtx = new AudioContext({ sampleRate: this.sampleRate });\n this.nextPlayTime = this.playbackCtx.currentTime;\n }\n\n if (this.playbackCtx.state === 'suspended') {\n this.playbackCtx.resume();\n }\n\n this.playLogCount++;\n if (this.playLogCount <= 5 || this.playLogCount % 250 === 0) {\n const int16Preview = new Int16Array(data);\n let maxVal = 0;\n for (let i = 0; i < Math.min(int16Preview.length, 100); i++) {\n const abs = Math.abs(int16Preview[i]);\n if (abs > maxVal) maxVal = abs;\n }\n console.log(`[AudioEngine] playPcm #${this.playLogCount} bytes=${data.byteLength} ctxState=${this.playbackCtx.state} sampleRate=${this.sampleRate} maxSample=${maxVal} nextPlayT=${this.nextPlayTime.toFixed(3)} ctxTime=${this.playbackCtx.currentTime.toFixed(3)}`);\n }\n\n const int16 = new Int16Array(data);\n const float32 = int16ToFloat32(int16);\n\n // Emit audio level\n const level = calculateRmsLevel(float32);\n this.onAudioLevel(level);\n\n // Schedule playback\n const buffer = this.playbackCtx.createBuffer(1, float32.length, this.sampleRate);\n buffer.getChannelData(0).set(float32);\n\n const source = this.playbackCtx.createBufferSource();\n source.buffer = buffer;\n source.connect(this.playbackCtx.destination);\n\n const now = this.playbackCtx.currentTime;\n if (this.nextPlayTime < now) {\n this.nextPlayTime = now + SCHEDULE_AHEAD_S;\n } else if (this.nextPlayTime - now > MAX_QUEUE_S) {\n this.nextPlayTime = now + SCHEDULE_AHEAD_S;\n }\n source.start(this.nextPlayTime);\n this.nextPlayTime += buffer.duration;\n }\n\n /** Start capturing microphone audio and sending as PCM Int16LE */\n async startMic(): Promise<void> {\n if (this.destroyed || this.micStream) return;\n\n this.micStream = await navigator.mediaDevices.getUserMedia({\n audio: {\n sampleRate: this.sampleRate,\n channelCount: 1,\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n },\n });\n\n this.micCtx = new AudioContext({ sampleRate: this.sampleRate });\n this.micSource = this.micCtx.createMediaStreamSource(this.micStream);\n\n // ScriptProcessorNode: 4096 samples per frame\n this.micProcessor = this.micCtx.createScriptProcessor(4096, 1, 1);\n this.micProcessor.onaudioprocess = (e) => {\n if (this.destroyed) return;\n const float32 = e.inputBuffer.getChannelData(0);\n const int16 = float32ToInt16(float32);\n this.onMicData(int16.buffer as ArrayBuffer);\n };\n\n this.micSource.connect(this.micProcessor);\n this.micProcessor.connect(this.micCtx.destination);\n }\n\n stopMic(): void {\n if (this.micProcessor) {\n this.micProcessor.disconnect();\n this.micProcessor = null;\n }\n if (this.micSource) {\n this.micSource.disconnect();\n this.micSource = null;\n }\n if (this.micStream) {\n for (const track of this.micStream.getTracks()) {\n track.stop();\n }\n this.micStream = null;\n }\n if (this.micCtx) {\n this.micCtx.close().catch(() => {});\n this.micCtx = null;\n }\n }\n\n /** Resume AudioContext (must be called from user gesture for autoplay policy) */\n resume(): void {\n if (!this.playbackCtx) {\n this.playbackCtx = new AudioContext({ sampleRate: this.sampleRate });\n this.nextPlayTime = this.playbackCtx.currentTime;\n }\n if (this.playbackCtx.state === 'suspended') {\n this.playbackCtx.resume();\n }\n }\n\n destroy(): void {\n this.destroyed = true;\n this.stopMic();\n if (this.playbackCtx) {\n this.playbackCtx.close().catch(() => {});\n this.playbackCtx = null;\n }\n }\n}\n","import type { VideoFrameInfo } from '../types';\n\nconst H264_FORMAT = 100;\nconst H264_CODEC = 'avc1.42001E';\nconst MAX_DECODER_ERRORS = 5;\n\nexport class VideoEngine {\n private canvas: HTMLCanvasElement | null = null;\n private ctx: CanvasRenderingContext2D | null = null;\n private localVideo: HTMLVideoElement | null = null;\n private localStream: MediaStream | null = null;\n private captureCanvas: HTMLCanvasElement | null = null;\n private captureCtx: CanvasRenderingContext2D | null = null;\n private tempCanvas: HTMLCanvasElement | null = null;\n private tempCtx: CanvasRenderingContext2D | null = null;\n private captureInterval: ReturnType<typeof setInterval> | null = null;\n private h264Decoder: VideoDecoder | null = null;\n private h264ErrorCount = 0;\n private orientationMap = new Map<number, number>();\n\n onCameraFrame: ((rgba: ArrayBuffer, width: number, height: number) => void) | null = null;\n onEncodedCameraFrame: ((h264: ArrayBuffer, width: number, height: number, timestampSec: number, isKeyFrame: boolean, latencyMs: number) => void) | null = null;\n private h264Encoder: VideoEncoder | null = null;\n private encoderKeyFrameInterval = 3000;\n private lastKeyFrameTs = 0;\n private h264NeedKeyFrame = false;\n\n setRemoteCanvas(canvas: HTMLCanvasElement): void {\n this.canvas = canvas;\n this.ctx = canvas.getContext('2d');\n }\n\n renderFrame(frame: VideoFrameInfo): void {\n if (!this.canvas || !this.ctx) return;\n const { width, height, data, orientation, format, isKeyFrame, timestamp } = frame;\n if (width <= 0 || height <= 0) return;\n\n if (format === H264_FORMAT) {\n this.decodeH264Frame(data, width, height, orientation, isKeyFrame, timestamp);\n return;\n }\n\n this.renderNV12Frame(data, width, height, orientation);\n }\n\n private h264GotKeyFrame = false;\n private h264FrameIndex = 0;\n\n private decodeH264Frame(\n data: ArrayBuffer, _width: number, _height: number,\n orientation: number, isKeyFrame: boolean, timestamp: number,\n ): void {\n if (data.byteLength === 0) return;\n\n if (!this.h264GotKeyFrame) {\n if (!isKeyFrame) return;\n this.h264GotKeyFrame = true;\n }\n\n if (!this.h264Decoder || this.h264Decoder.state === 'closed') {\n if (this.h264ErrorCount >= MAX_DECODER_ERRORS) return;\n this.h264Decoder = this.createH264Decoder();\n if (!this.h264Decoder) return;\n this.h264GotKeyFrame = false;\n if (!isKeyFrame) return;\n this.h264GotKeyFrame = true;\n }\n\n this.h264FrameIndex++;\n const tsUs = this.h264FrameIndex * 66666;\n this.orientationMap.set(tsUs, orientation);\n\n try {\n this.h264Decoder.decode(new EncodedVideoChunk({\n type: isKeyFrame ? 'key' : 'delta',\n timestamp: tsUs,\n data,\n }));\n } catch (e) {\n this.h264ErrorCount++;\n this.h264GotKeyFrame = false;\n }\n }\n\n private createH264Decoder(): VideoDecoder | null {\n if (typeof globalThis.VideoDecoder !== 'function') return null;\n\n try {\n const decoder = new VideoDecoder({\n output: (vf) => {\n try {\n if (!this.canvas || !this.ctx) { vf.close(); return; }\n const orientation = this.orientationMap.get(vf.timestamp) ?? 1;\n this.orientationMap.delete(vf.timestamp);\n\n const w = vf.codedWidth;\n const h = vf.codedHeight;\n const isRotated = orientation === 2 || orientation === 4;\n const displayW = isRotated ? h : w;\n const displayH = isRotated ? w : h;\n\n if (this.canvas.width !== displayW || this.canvas.height !== displayH) {\n this.canvas.width = displayW;\n this.canvas.height = displayH;\n }\n\n this.ctx!.save();\n if (orientation === 2) {\n this.ctx!.translate(displayW, 0);\n this.ctx!.rotate(Math.PI / 2);\n } else if (orientation === 3) {\n this.ctx!.translate(displayW, displayH);\n this.ctx!.rotate(Math.PI);\n } else if (orientation === 4) {\n this.ctx!.translate(0, displayH);\n this.ctx!.rotate(-Math.PI / 2);\n }\n this.ctx!.drawImage(vf, 0, 0);\n this.ctx!.restore();\n } finally {\n vf.close();\n }\n },\n error: () => {\n this.h264ErrorCount++;\n this.orientationMap.clear();\n },\n });\n\n decoder.configure({ codec: H264_CODEC, optimizeForLatency: true });\n this.h264ErrorCount = 0;\n return decoder;\n } catch {\n return null;\n }\n }\n\n private renderNV12Frame(data: ArrayBuffer, width: number, height: number, orientation: number): void {\n if (!this.canvas || !this.ctx) return;\n\n const isRotated = orientation === 2 || orientation === 4;\n const displayW = isRotated ? height : width;\n const displayH = isRotated ? width : height;\n\n if (this.canvas.width !== displayW || this.canvas.height !== displayH) {\n this.canvas.width = displayW;\n this.canvas.height = displayH;\n }\n\n if (typeof (globalThis as any).VideoFrame === 'function') {\n try {\n const vf = new (globalThis as any).VideoFrame(new Uint8Array(data), {\n format: 'NV12',\n codedWidth: width,\n codedHeight: height,\n timestamp: 0,\n });\n this.ctx.save();\n if (orientation === 2) {\n this.ctx.translate(displayW, 0);\n this.ctx.rotate(Math.PI / 2);\n } else if (orientation === 3) {\n this.ctx.translate(displayW, displayH);\n this.ctx.rotate(Math.PI);\n } else if (orientation === 4) {\n this.ctx.translate(0, displayH);\n this.ctx.rotate(-Math.PI / 2);\n }\n this.ctx.drawImage(vf, 0, 0);\n this.ctx.restore();\n vf.close();\n return;\n } catch {\n // fallback\n }\n }\n\n const nv12 = new Uint8Array(data);\n const rgba = this.nv12ToRgba(nv12, width, height);\n const imgData = new ImageData(new Uint8ClampedArray(rgba.buffer as ArrayBuffer), width, height);\n\n if (orientation >= 2 && orientation <= 4) {\n if (!this.tempCanvas) {\n this.tempCanvas = document.createElement('canvas');\n this.tempCtx = this.tempCanvas.getContext('2d');\n }\n this.tempCanvas.width = width;\n this.tempCanvas.height = height;\n this.tempCtx!.putImageData(imgData, 0, 0);\n\n this.ctx.save();\n if (orientation === 2) {\n this.ctx.translate(displayW, 0);\n this.ctx.rotate(Math.PI / 2);\n } else if (orientation === 3) {\n this.ctx.translate(displayW, displayH);\n this.ctx.rotate(Math.PI);\n } else if (orientation === 4) {\n this.ctx.translate(0, displayH);\n this.ctx.rotate(-Math.PI / 2);\n }\n this.ctx.drawImage(this.tempCanvas, 0, 0);\n this.ctx.restore();\n } else {\n this.ctx.putImageData(imgData, 0, 0);\n }\n }\n\n async startCamera(videoEl: HTMLVideoElement, width = 640, height = 480, fps = 15): Promise<void> {\n this.localVideo = videoEl;\n\n const stream = await navigator.mediaDevices.getUserMedia({\n video: { width: { ideal: width }, height: { ideal: height }, frameRate: { ideal: fps } },\n audio: false,\n });\n this.localStream = stream;\n videoEl.srcObject = stream;\n videoEl.muted = true;\n await videoEl.play();\n\n const useH264 = this.canUseH264Encoder();\n if (useH264) {\n this.startH264Capture(stream, width, height, fps);\n } else {\n this.captureCanvas = document.createElement('canvas');\n this.captureCanvas.width = width;\n this.captureCanvas.height = height;\n this.captureCtx = this.captureCanvas.getContext('2d', { willReadFrequently: true });\n this.captureInterval = setInterval(() => this.captureFrameRaw(), Math.floor(1000 / fps));\n }\n }\n\n stopCamera(): void {\n if (this.captureInterval) {\n clearInterval(this.captureInterval);\n this.captureInterval = null;\n }\n if (this.h264Encoder && this.h264Encoder.state !== 'closed') {\n try { this.h264Encoder.close(); } catch {}\n }\n this.h264Encoder = null;\n if (this.localStream) {\n this.localStream.getTracks().forEach(t => t.stop());\n this.localStream = null;\n }\n if (this.localVideo) {\n this.localVideo.srcObject = null;\n this.localVideo = null;\n }\n this.captureCanvas = null;\n this.captureCtx = null;\n }\n\n private canUseH264Encoder(): boolean {\n return typeof globalThis.VideoEncoder === 'function'\n && typeof (globalThis as any).MediaStreamTrackProcessor === 'function';\n }\n\n private startH264Capture(stream: MediaStream, width: number, height: number, fps: number): void {\n const track = stream.getVideoTracks()[0];\n if (!track) return;\n\n let encodeW = width;\n let encodeH = height;\n let frameCount = 0;\n const submitTimes = new Map<number, number>();\n\n this.h264Encoder = new VideoEncoder({\n output: (chunk, meta) => {\n if (!this.onEncodedCameraFrame) return;\n const buf = new ArrayBuffer(chunk.byteLength);\n chunk.copyTo(buf);\n const isKey = chunk.type === 'key';\n const codedW = meta?.decoderConfig?.codedWidth ?? encodeW;\n const codedH = meta?.decoderConfig?.codedHeight ?? encodeH;\n let latencyMs = 0;\n const submitted = submitTimes.get(chunk.timestamp);\n if (submitted != null) {\n submitTimes.delete(chunk.timestamp);\n latencyMs = Date.now() - submitted;\n }\n const tsSec = chunk.timestamp / 1e3;\n this.onEncodedCameraFrame(buf, codedW, codedH, tsSec, isKey, latencyMs);\n },\n error: (e) => { console.error('[VideoEngine] encoder error:', e); },\n });\n\n this.h264Encoder.configure({\n codec: 'avc1.42001f',\n width: encodeW,\n height: encodeH,\n bitrate: 500000,\n framerate: fps,\n latencyMode: 'realtime',\n bitrateMode: 'constant',\n avc: { format: 'annexb' },\n } as any);\n\n const processor = new (globalThis as any).MediaStreamTrackProcessor({ track });\n const reader = processor.readable.getReader();\n\n const readLoop = async () => {\n while (this.h264Encoder && this.h264Encoder.state !== 'closed') {\n try {\n const { value: frame, done } = await reader.read();\n if (done || !frame) break;\n if (this.h264Encoder.state !== 'configured') { frame.close(); continue; }\n\n const now = Date.now();\n const sinceLastKey = now - this.lastKeyFrameTs;\n const needKey = this.h264NeedKeyFrame || sinceLastKey >= this.encoderKeyFrameInterval || frameCount === 0;\n\n submitTimes.set(frame.timestamp, now);\n this.h264Encoder.encode(frame, { keyFrame: needKey });\n frame.close();\n\n frameCount++;\n if (needKey) {\n this.lastKeyFrameTs = now;\n this.h264NeedKeyFrame = false;\n }\n } catch { break; }\n }\n };\n readLoop();\n }\n\n private captureFrameRaw(): void {\n if (!this.captureCtx || !this.captureCanvas || !this.localVideo || !this.onCameraFrame) return;\n if (this.localVideo.readyState < 2) return;\n\n const w = this.captureCanvas.width;\n const h = this.captureCanvas.height;\n this.captureCtx.drawImage(this.localVideo, 0, 0, w, h);\n const imgData = this.captureCtx.getImageData(0, 0, w, h);\n this.onCameraFrame(imgData.data.buffer, w, h);\n }\n\n private nv12ToRgba(nv12: Uint8Array, width: number, height: number): Uint8ClampedArray {\n const rgba = new Uint8ClampedArray(width * height * 4);\n const yPlaneSize = width * height;\n\n for (let j = 0; j < height; j++) {\n for (let i = 0; i < width; i++) {\n const yIdx = j * width + i;\n const uvIdx = yPlaneSize + (j >> 1) * width + (i & ~1);\n\n const y = nv12[yIdx];\n const u = nv12[uvIdx] - 128;\n const v = nv12[uvIdx + 1] - 128;\n\n const rgbaIdx = yIdx * 4;\n rgba[rgbaIdx] = clamp(y + 1.402 * v);\n rgba[rgbaIdx + 1] = clamp(y - 0.344 * u - 0.714 * v);\n rgba[rgbaIdx + 2] = clamp(y + 1.772 * u);\n rgba[rgbaIdx + 3] = 255;\n }\n }\n return rgba;\n }\n\n clearCanvas(): void {\n if (this.canvas && this.ctx) {\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n }\n }\n\n destroy(): void {\n this.stopCamera();\n if (this.h264Decoder && this.h264Decoder.state !== 'closed') {\n try { this.h264Decoder.close(); } catch {}\n }\n this.h264Decoder = null;\n this.orientationMap.clear();\n this.canvas = null;\n this.ctx = null;\n }\n}\n\nfunction clamp(v: number): number {\n return v < 0 ? 0 : v > 255 ? 255 : v | 0;\n}\n","import type { CallInfo, CallState } from '../types';\n\nexport class CallStateManager {\n private calls = new Map<string, CallInfo>();\n\n addCall(call: CallInfo): void {\n this.calls.set(call.callId, { ...call });\n }\n\n updateState(callId: string, state: CallState): void {\n const call = this.calls.get(callId);\n if (!call) return;\n call.state = state;\n if (state === 'ended') {\n this.calls.delete(callId);\n }\n }\n\n updateIsVideo(callId: string, isVideo: boolean): void {\n const call = this.calls.get(callId);\n if (call) {\n call.isVideo = isVideo;\n }\n }\n\n removeCall(callId: string): void {\n this.calls.delete(callId);\n }\n\n getCall(callId: string): CallInfo | undefined {\n return this.calls.get(callId);\n }\n\n getActiveCall(): CallInfo | undefined {\n for (const call of this.calls.values()) {\n if (call.state === 'accepted' || call.state === 'active') {\n return call;\n }\n }\n return undefined;\n }\n\n getRingingCalls(): CallInfo[] {\n const result: CallInfo[] = [];\n for (const call of this.calls.values()) {\n if (call.state === 'ringing' || call.state === 'preaccepted') {\n result.push(call);\n }\n }\n return result;\n }\n\n getAllCalls(): CallInfo[] {\n return Array.from(this.calls.values());\n }\n\n hasActiveCalls(): boolean {\n for (const call of this.calls.values()) {\n if (call.state !== 'ended') return true;\n }\n return false;\n }\n\n clear(): void {\n this.calls.clear();\n }\n}\n","import type { ZAPICallTheme } from '../types';\n\nexport function buildCSS(theme: ZAPICallTheme): string {\n const light = theme.mode === 'light';\n\n const primary = theme.primaryColor || '#00a884';\n const danger = theme.dangerColor || '#f44336';\n const bg = theme.backgroundColor || (light ? '#f0f2f5' : '#202c33');\n const surface = theme.surfaceColor || (light ? '#ffffff' : '#111b21');\n const text = theme.textColor || (light ? '#111b21' : '#e9edef');\n const textSec = theme.textSecondaryColor || (light ? '#667781' : '#8696a0');\n const radius = theme.borderRadius || '16px';\n const font = theme.fontFamily || \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\";\n\n // Theme-aware overlays and shadows\n const overlay = light ? 'rgba(0,0,0,0.06)' : 'rgba(255,255,255,0.08)';\n const overlayHover = light ? 'rgba(0,0,0,0.1)' : 'rgba(255,255,255,0.1)';\n const overlayActive = light ? 'rgba(0,0,0,0.14)' : 'rgba(255,255,255,0.15)';\n const shadow = light ? 'rgba(0,0,0,0.12)' : 'rgba(0,0,0,0.3)';\n const shadowLg = light ? 'rgba(0,0,0,0.16)' : 'rgba(0,0,0,0.4)';\n const border = light ? 'rgba(0,0,0,0.08)' : 'rgba(255,255,255,0.06)';\n const borderLight = light ? 'rgba(0,0,0,0.12)' : 'rgba(255,255,255,0.1)';\n\n return `\n :host {\n all: initial;\n font-family: ${font};\n color: ${text};\n --primary: ${primary};\n --danger: ${danger};\n --bg: ${bg};\n --surface: ${surface};\n --text: ${text};\n --text-sec: ${textSec};\n --radius: ${radius};\n }\n\n * { margin: 0; padding: 0; box-sizing: border-box; }\n\n .zapi-call-root {\n position: fixed;\n z-index: 2147483647;\n font-family: ${font};\n }\n .zapi-call-root.bottom-right { bottom: 20px; right: 20px; }\n .zapi-call-root.bottom-left { bottom: 20px; left: 20px; }\n .zapi-call-root.top-right { top: 20px; right: 20px; }\n .zapi-call-root.top-left { top: 20px; left: 20px; }\n\n /* Bubble */\n .bubble {\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: var(--primary);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 4px 12px ${shadow};\n transition: transform 0.2s, box-shadow 0.2s;\n position: relative;\n user-select: none;\n }\n .bubble:hover { transform: scale(1.08); box-shadow: 0 6px 20px ${shadowLg}; }\n .bubble:active { transform: scale(0.95); }\n .bubble svg { width: 26px; height: 26px; color: #fff; }\n\n .bubble .badge {\n position: absolute;\n top: -2px;\n right: -2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--danger);\n color: #fff;\n font-size: 11px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n display: none;\n }\n .bubble .badge.visible { display: flex; }\n\n .bubble .conn-dot {\n position: absolute;\n bottom: 2px;\n right: 2px;\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: #f44336;\n border: 2px solid var(--primary);\n }\n .bubble .conn-dot.connected { background: #4caf50; }\n\n .bubble.ringing {\n animation: bubble-pulse 1.5s ease-in-out infinite;\n }\n @keyframes bubble-pulse {\n 0%, 100% { box-shadow: 0 4px 12px ${shadow}; }\n 50% { box-shadow: 0 4px 12px ${shadow}, 0 0 0 12px rgba(0,168,132,0.2); }\n }\n\n /* Panel */\n .panel {\n position: absolute;\n bottom: 66px;\n right: 0;\n width: 360px;\n max-height: 560px;\n background: var(--surface);\n border-radius: var(--radius);\n box-shadow: 0 8px 32px ${shadowLg};\n overflow: hidden;\n transform: translateY(10px);\n opacity: 0;\n pointer-events: none;\n transition: transform 0.25s ease, opacity 0.25s ease;\n display: flex;\n flex-direction: column;\n }\n .panel.open {\n transform: translateY(0);\n opacity: 1;\n pointer-events: auto;\n }\n .zapi-call-root.bottom-left .panel { right: auto; left: 0; }\n .zapi-call-root.top-right .panel { bottom: auto; top: 66px; }\n .zapi-call-root.top-left .panel { bottom: auto; top: 66px; right: auto; left: 0; }\n\n /* Panel header with tabs */\n .panel-header {\n background: var(--bg);\n border-bottom: 1px solid ${border};\n flex-shrink: 0;\n }\n .panel-header-top {\n padding: 10px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n .panel-header-top h3 {\n font-size: 15px;\n font-weight: 600;\n color: var(--text);\n }\n .panel-header .close-btn {\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: var(--text-sec);\n cursor: pointer;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s;\n }\n .panel-header .close-btn:hover { background: ${overlay}; }\n .panel-header .close-btn svg { width: 18px; height: 18px; }\n\n /* Tabs */\n .tabs {\n display: flex;\n padding: 0 8px;\n }\n .tab {\n flex: 1;\n padding: 10px 8px;\n border: none;\n background: transparent;\n color: var(--text-sec);\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: color 0.2s;\n font-family: inherit;\n }\n .tab svg { width: 16px; height: 16px; }\n .tab:hover { color: var(--text); }\n .tab.active { color: var(--primary); }\n .tab.active::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 16px;\n right: 16px;\n height: 2px;\n background: var(--primary);\n border-radius: 2px 2px 0 0;\n }\n\n /* Panel body / views */\n .panel-body {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n min-height: 0;\n }\n .view {\n display: none;\n animation: view-in 0.2s ease;\n }\n .view.active { display: block; }\n @keyframes view-in {\n from { opacity: 0; transform: translateY(6px); }\n to { opacity: 1; transform: translateY(0); }\n }\n\n /* ── Dialer view ── */\n .dialer {\n padding: 8px 16px 14px;\n display: flex;\n flex-direction: column;\n align-items: center;\n }\n .dialer-display {\n width: 100%;\n height: 56px;\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n margin-bottom: 8px;\n }\n .dialer-input {\n width: 100%;\n background: transparent;\n border: none;\n padding: 0 40px;\n color: var(--text);\n font-size: 28px;\n font-weight: 300;\n font-family: inherit;\n text-align: center;\n letter-spacing: 1.5px;\n outline: none;\n font-variant-numeric: tabular-nums;\n caret-color: var(--primary);\n }\n .dialer-input::placeholder { color: var(--text-sec); font-size: 16px; font-weight: 400; letter-spacing: 0; }\n .dialer-input.error::placeholder { color: #e74c3c; }\n .backspace-btn {\n position: absolute;\n right: 0;\n width: 36px;\n height: 36px;\n border: none;\n background: transparent;\n color: var(--text-sec);\n cursor: pointer;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s, color 0.2s;\n }\n .backspace-btn:hover { background: ${overlay}; color: var(--text); }\n .backspace-btn svg { width: 20px; height: 20px; }\n\n /* Numpad */\n .numpad {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 6px;\n width: 100%;\n max-width: 240px;\n margin-bottom: 12px;\n }\n .numpad-key {\n width: 60px;\n height: 60px;\n border-radius: 50%;\n border: none;\n background: var(--bg);\n color: var(--text);\n font-size: 22px;\n font-weight: 400;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n transition: background 0.15s, transform 0.1s;\n user-select: none;\n font-family: inherit;\n justify-self: center;\n line-height: 1;\n }\n .numpad-key:hover { background: ${overlayHover}; }\n .numpad-key:active { transform: scale(0.92); background: ${overlayActive}; }\n .numpad-key .sub {\n font-size: 8px;\n color: var(--text-sec);\n letter-spacing: 1.5px;\n margin-top: 1px;\n font-weight: 600;\n }\n\n /* Call buttons */\n .call-btns {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n .call-btn {\n width: 56px;\n height: 56px;\n border-radius: 50%;\n border: none;\n background: var(--primary);\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 16px rgba(0,168,132,0.3);\n transition: transform 0.15s, box-shadow 0.15s;\n }\n .call-btn:hover { transform: scale(1.08); box-shadow: 0 6px 24px rgba(0,168,132,0.4); }\n .call-btn:active { transform: scale(0.95); }\n .call-btn svg { width: 26px; height: 26px; }\n .call-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n box-shadow: 0 4px 16px rgba(0,168,132,0.15);\n }\n .video-call-btn {\n background: #2196f3;\n box-shadow: 0 4px 16px rgba(33,150,243,0.3);\n }\n .video-call-btn:hover { box-shadow: 0 6px 24px rgba(33,150,243,0.4); }\n\n /* ── Calls view ── */\n .calls-view {\n padding: 8px;\n }\n\n .empty-state {\n padding: 40px 16px;\n text-align: center;\n color: var(--text-sec);\n font-size: 13px;\n }\n .empty-state .icon {\n font-size: 36px;\n margin-bottom: 8px;\n }\n\n /* Call Card */\n .call-card {\n background: var(--bg);\n border-radius: 12px;\n padding: 14px;\n margin-bottom: 8px;\n animation: card-in 0.3s ease;\n }\n .call-card.ended {\n opacity: 0.5;\n animation: card-out 0.5s ease forwards;\n }\n @keyframes card-in {\n from { transform: translateY(-8px); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n @keyframes card-out {\n to { transform: translateY(8px); opacity: 0; }\n }\n\n .call-card-top {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 10px;\n }\n\n .avatar {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n background: var(--surface);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n }\n .avatar svg { width: 22px; height: 22px; color: var(--text-sec); }\n .avatar .avatar-img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }\n\n .call-info { flex: 1; min-width: 0; }\n .call-phone {\n font-size: 15px;\n font-weight: 600;\n color: var(--text);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .call-meta {\n font-size: 12px;\n color: var(--text-sec);\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 2px;\n }\n .call-meta svg { width: 13px; height: 13px; }\n\n .state-badge {\n padding: 3px 8px;\n border-radius: 6px;\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n flex-shrink: 0;\n }\n .state-badge.ringing {\n background: #f9a825;\n color: #000;\n animation: badge-pulse 1.5s ease-in-out infinite;\n }\n .state-badge.preaccepted { background: #ff9800; color: #000; }\n .state-badge.accepted { background: #2196f3; color: #fff; }\n .state-badge.active { background: var(--primary); color: #fff; }\n .state-badge.ended { background: var(--danger); color: #fff; }\n @keyframes badge-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n\n .timer {\n font-size: 22px;\n font-weight: 300;\n text-align: center;\n margin: 8px 0;\n font-variant-numeric: tabular-nums;\n color: var(--text);\n }\n\n .call-actions {\n display: flex;\n gap: 8px;\n margin-top: 8px;\n }\n\n .btn {\n flex: 1;\n padding: 10px 16px;\n border: none;\n border-radius: 24px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: transform 0.15s, opacity 0.15s;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n font-family: inherit;\n }\n .btn:hover { transform: scale(1.03); }\n .btn:active { transform: scale(0.97); }\n .btn svg { width: 18px; height: 18px; }\n .btn-accept { background: var(--primary); color: #fff; }\n .btn-reject { background: var(--danger); color: #fff; }\n .btn-mute {\n width: 44px;\n height: 44px;\n flex: none;\n border-radius: 50%;\n background: var(--bg);\n border: 1px solid ${borderLight};\n color: var(--text);\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: background 0.2s;\n }\n .btn-mute:hover { background: ${overlay}; }\n .btn-mute.muted { background: var(--danger); color: #fff; border-color: transparent; }\n .btn-mute svg { width: 20px; height: 20px; }\n\n /* ── In-Call view ── */\n .incall-view {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n }\n .incall-view .audio-call-ui {\n padding: 24px 16px;\n }\n .incall-avatar {\n width: 80px;\n height: 80px;\n border-radius: 50%;\n background: var(--bg);\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 16px;\n }\n .incall-avatar svg { width: 40px; height: 40px; color: var(--text-sec); }\n .incall-avatar .avatar-img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }\n .incall-phone {\n font-size: 20px;\n font-weight: 600;\n color: var(--text);\n margin-bottom: 4px;\n }\n .incall-state {\n font-size: 14px;\n color: var(--text-sec);\n margin-bottom: 4px;\n }\n .incall-timer {\n font-size: 28px;\n font-weight: 300;\n color: var(--text);\n font-variant-numeric: tabular-nums;\n margin-bottom: 20px;\n }\n\n /* Audio level bar */\n .audio-level-wrap {\n width: 100%;\n max-width: 200px;\n height: 6px;\n background: var(--bg);\n border-radius: 3px;\n overflow: hidden;\n margin-bottom: 28px;\n }\n .audio-level-bar {\n height: 100%;\n width: 0%;\n background: var(--primary);\n border-radius: 3px;\n transition: width 0.1s ease;\n }\n\n /* In-call controls */\n .incall-controls {\n display: flex;\n align-items: center;\n gap: 32px;\n }\n .incall-btn {\n width: 56px;\n height: 56px;\n border-radius: 50%;\n border: none;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: transform 0.15s;\n }\n .incall-btn:hover { transform: scale(1.08); }\n .incall-btn:active { transform: scale(0.95); }\n .incall-btn svg { width: 24px; height: 24px; }\n .incall-btn-mute {\n background: var(--bg);\n color: var(--text);\n border: 1px solid ${borderLight};\n }\n .incall-btn-mute.muted {\n background: var(--danger);\n color: #fff;\n border-color: transparent;\n }\n .incall-btn-camera {\n background: var(--bg);\n color: var(--text);\n border: 1px solid ${borderLight};\n }\n .incall-btn-camera:hover { background: ${overlay}; }\n .incall-btn-camera.muted {\n color: var(--text-sec);\n }\n .incall-btn-end {\n background: var(--danger);\n color: #fff;\n width: 64px;\n height: 64px;\n }\n .incall-btn-end svg { width: 28px; height: 28px; }\n\n /* ── Video Call ── */\n .audio-call-ui {\n display: flex;\n flex-direction: column;\n align-items: center;\n }\n .video-container {\n position: relative;\n width: 100%;\n height: 420px;\n overflow: hidden;\n background: #000;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 0 0 12px 12px;\n }\n .remote-video {\n max-width: 100%;\n max-height: 100%;\n display: block;\n object-fit: contain;\n }\n .video-overlay-top {\n position: absolute;\n top: 0; left: 0; right: 0;\n padding: 16px;\n background: linear-gradient(to bottom, rgba(0,0,0,0.6), transparent);\n z-index: 2;\n }\n .video-caller-info {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n .video-phone {\n font-size: 15px;\n font-weight: 600;\n color: #fff;\n text-shadow: 0 1px 3px rgba(0,0,0,0.5);\n }\n .video-timer {\n font-size: 14px;\n font-weight: 500;\n color: rgba(255,255,255,0.85);\n font-variant-numeric: tabular-nums;\n text-shadow: 0 1px 3px rgba(0,0,0,0.5);\n }\n .video-overlay-bottom {\n position: absolute;\n bottom: 0; left: 0; right: 0;\n padding: 20px;\n background: linear-gradient(to top, rgba(0,0,0,0.6), transparent);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 32px;\n z-index: 2;\n }\n .video-overlay-bottom .incall-btn {\n backdrop-filter: blur(8px);\n }\n .video-btn-mute {\n background: rgba(255,255,255,0.2) !important;\n color: #fff !important;\n border: none !important;\n }\n .video-btn-mute.muted {\n background: var(--danger) !important;\n }\n .video-btn-camera {\n background: rgba(255,255,255,0.2) !important;\n color: #fff !important;\n border: none !important;\n }\n .video-btn-camera.muted {\n background: rgba(255,255,255,0.1) !important;\n color: rgba(255,255,255,0.5) !important;\n }\n .video-btn-end {\n background: var(--danger) !important;\n color: #fff !important;\n }\n .video-btn-end svg { width: 28px; height: 28px; }\n\n /* ── Contacts view ── */\n .contacts-wrapper {\n display: flex;\n flex-direction: column;\n height: 400px;\n }\n .contacts-search-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n border-bottom: 1px solid ${border};\n flex-shrink: 0;\n }\n .contacts-search-input-wrap {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 8px;\n background: var(--bg);\n border-radius: 20px;\n padding: 0 12px;\n height: 36px;\n }\n .contacts-search-input-wrap svg {\n width: 16px;\n height: 16px;\n color: var(--text-sec);\n flex-shrink: 0;\n }\n .contacts-search-input {\n flex: 1;\n border: none;\n background: transparent;\n color: var(--text);\n font-size: 13px;\n font-family: inherit;\n outline: none;\n }\n .contacts-search-input::placeholder { color: var(--text-sec); }\n .contacts-refresh-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n color: var(--text-sec);\n cursor: pointer;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s, color 0.2s;\n flex-shrink: 0;\n }\n .contacts-refresh-btn:hover { background: ${overlay}; color: var(--text); }\n .contacts-refresh-btn svg { width: 18px; height: 18px; }\n\n .contacts-list {\n flex: 1;\n overflow-y: auto;\n padding: 4px 8px;\n }\n .contacts-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 16px;\n color: var(--text-sec);\n font-size: 13px;\n gap: 12px;\n }\n .spinner {\n width: 24px;\n height: 24px;\n border: 3px solid ${overlay};\n border-top-color: var(--primary);\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n @keyframes spin { to { transform: rotate(360deg); } }\n\n .contact-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 8px;\n border-radius: 10px;\n cursor: default;\n transition: background 0.15s;\n }\n .contact-item:hover { background: ${overlay}; }\n .contact-avatar {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: var(--bg);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n overflow: hidden;\n font-size: 14px;\n font-weight: 600;\n color: var(--text-sec);\n }\n .contact-avatar img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n .contact-info {\n flex: 1;\n min-width: 0;\n }\n .contact-name {\n font-size: 14px;\n font-weight: 500;\n color: var(--text);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .contact-phone {\n font-size: 12px;\n color: var(--text-sec);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .contact-call-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: var(--primary);\n color: #fff;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n flex-shrink: 0;\n transition: transform 0.15s;\n }\n .contact-call-btn:hover { transform: scale(1.1); }\n .contact-call-btn:active { transform: scale(0.95); }\n .contact-call-btn svg { width: 16px; height: 16px; }\n\n /* Hide header tabs during video call */\n .incall-view .video-container[style*=\"flex\"] ~ .panel-header { display: none; }\n `;\n}\n","export const ICON_PHONE = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M6.62 10.79a15.05 15.05 0 006.59 6.59l2.2-2.2a1 1 0 011.01-.24c1.12.37 2.33.57 3.57.57a1 1 0 011 1V20a1 1 0 01-1 1A17 17 0 013 4a1 1 0 011-1h3.5a1 1 0 011 1c0 1.25.2 2.45.57 3.57a1 1 0 01-.25 1.02l-2.2 2.2z\"/></svg>`;\n\nexport const ICON_PHONE_END = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 9c-1.6 0-3.15.25-4.6.72v3.1c0 .39-.23.74-.56.9-.98.49-1.87 1.12-2.66 1.85-.18.18-.43.28-.7.28-.28 0-.53-.11-.71-.29L.29 13.08a.956.956 0 010-1.36C3.34 8.75 7.46 7 12 7s8.66 1.75 11.71 4.72c.18.18.29.44.29.71 0 .28-.11.53-.29.71l-2.48 2.48c-.18.18-.43.29-.71.29-.27 0-.52-.11-.7-.28a11.27 11.27 0 00-2.67-1.85.99.99 0 01-.56-.9v-3.1C15.15 9.25 13.6 9 12 9z\"/></svg>`;\n\nexport const ICON_PHONE_ACCEPT = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M20.01 15.38c-1.23 0-2.42-.2-3.53-.56a.977.977 0 00-1.01.24l-1.57 1.97c-2.83-1.35-5.48-3.9-6.89-6.83l1.95-1.66c.27-.28.35-.67.24-1.02-.37-1.11-.56-2.3-.56-3.53 0-.54-.45-.99-.99-.99H4.19C3.65 3 3 3.24 3 3.99 3 13.28 10.73 21 20.01 21c.71 0 .99-.63.99-1.18v-3.45c0-.54-.45-.99-.99-.99z\"/></svg>`;\n\nexport const ICON_MIC = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm-1-9c0-.55.45-1 1-1s1 .45 1 1v6c0 .55-.45 1-1 1s-1-.45-1-1V5z\"/><path d=\"M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z\"/></svg>`;\n\nexport const ICON_MIC_OFF = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M19 11h-1.7c0 .74-.16 1.43-.43 2.05l1.23 1.23c.56-.98.9-2.09.9-3.28zm-4.02.17c0-.06.02-.11.02-.17V5c0-1.66-1.34-3-3-3S9 3.34 9 5v.18l5.98 5.99zM4.27 3L3 4.27l6.01 6.01V11c0 1.66 1.33 3 2.99 3 .22 0 .44-.03.65-.08l1.66 1.66c-.71.33-1.5.52-2.31.52-2.76 0-5.3-2.1-5.3-5.1H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c.91-.13 1.77-.45 2.54-.9L19.73 21 21 19.73 4.27 3z\"/></svg>`;\n\nexport const ICON_USER = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z\"/></svg>`;\n\nexport const ICON_VIDEO = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M17 10.5V7c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11l-4 4z\"/></svg>`;\n\nexport const ICON_VIDEO_OFF = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M21 6.5l-4 4V7c0-.55-.45-1-1-1H9.82L21 17.18V6.5zM3.27 2L2 3.27 4.73 6H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.21 0 .39-.08.54-.18L19.73 21 21 19.73 3.27 2z\"/></svg>`;\n\nexport const ICON_CLOSE = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z\"/></svg>`;\n\nexport const ICON_BACKSPACE = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59 12.59 12 9 8.41 10.41 7 14 10.59 17.59 7 19 8.41 15.41 12 19 15.59z\"/></svg>`;\n\nexport const ICON_DIALPAD = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 19c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zM6 1c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12-8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-6 8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z\"/></svg>`;\n\nexport const ICON_CALL_LIST = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M20 15.5c-1.25 0-2.45-.2-3.57-.57a1.02 1.02 0 00-1.02.24l-2.2 2.2a15.045 15.045 0 01-6.59-6.59l2.2-2.21a.96.96 0 00.25-1A11.36 11.36 0 018.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM19 12h2c0-4.97-4.03-9-9-9v2c3.87 0 7 3.13 7 7zm-4 0h2c0-2.76-2.24-5-5-5v2c1.66 0 3 1.34 3 3z\"/></svg>`;\n\nexport const ICON_CONTACTS = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5s-3 1.34-3 3 1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z\"/></svg>`;\n\nexport const ICON_SEARCH = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M15.5 14h-.79l-.28-.27a6.5 6.5 0 001.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 00-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 005.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z\"/></svg>`;\n\nexport const ICON_REFRESH = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M17.65 6.35A7.958 7.958 0 0012 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08A5.99 5.99 0 0112 18c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z\"/></svg>`;\n","/** Format millisecond duration as MM:SS */\nexport function formatDuration(ms: number): string {\n const totalSec = Math.floor(ms / 1000);\n const min = Math.floor(totalSec / 60);\n const sec = totalSec % 60;\n return `${String(min).padStart(2, '0')}:${String(sec).padStart(2, '0')}`;\n}\n\n/** Format phone number with country code for display */\nexport function formatPhone(phone: string): string {\n if (!phone || phone === 'unknown') return phone;\n // Strip non-digits\n const digits = phone.replace(/\\D/g, '');\n if (digits.length <= 4) return phone;\n // Brazilian format: +55 (XX) XXXXX-XXXX\n if (digits.length === 13 && digits.startsWith('55')) {\n return `+${digits.slice(0, 2)} (${digits.slice(2, 4)}) ${digits.slice(4, 9)}-${digits.slice(9)}`;\n }\n if (digits.length === 12 && digits.startsWith('55')) {\n return `+${digits.slice(0, 2)} (${digits.slice(2, 4)}) ${digits.slice(4, 8)}-${digits.slice(8)}`;\n }\n // Generic: +CC XXXXXXXX\n return `+${digits}`;\n}\n","import type { CallInfo, ContactInfo, ZAPICallTheme, WidgetPosition } from '../types';\nimport { buildCSS } from './CallWidget.css';\nimport {\n ICON_PHONE,\n ICON_PHONE_ACCEPT,\n ICON_PHONE_END,\n ICON_MIC,\n ICON_MIC_OFF,\n ICON_USER,\n ICON_VIDEO,\n ICON_VIDEO_OFF,\n ICON_CLOSE,\n ICON_BACKSPACE,\n ICON_DIALPAD,\n ICON_CALL_LIST,\n ICON_CONTACTS,\n ICON_SEARCH,\n ICON_REFRESH,\n} from './icons';\nimport { formatDuration, formatPhone } from '../utils/format';\n\ntype ViewName = 'dialer' | 'calls' | 'contacts' | 'incall';\n\nconst NUMPAD_KEYS: { digit: string; sub: string }[] = [\n { digit: '1', sub: '' },\n { digit: '2', sub: 'ABC' },\n { digit: '3', sub: 'DEF' },\n { digit: '4', sub: 'GHI' },\n { digit: '5', sub: 'JKL' },\n { digit: '6', sub: 'MNO' },\n { digit: '7', sub: 'PQRS' },\n { digit: '8', sub: 'TUV' },\n { digit: '9', sub: 'WXYZ' },\n { digit: '*', sub: '' },\n { digit: '0', sub: '+' },\n { digit: '#', sub: '' },\n];\n\nexport interface CallWidgetConfig {\n position: WidgetPosition;\n theme: ZAPICallTheme;\n showVideoDialButton: boolean;\n onAccept: (callId: string) => void;\n onReject: (callId: string) => void;\n onMute: (muted: boolean) => void;\n onCamera: (enabled: boolean) => void;\n onResume: () => void;\n onMakeCall: (number: string, isVideo: boolean) => void;\n onRequestContacts: () => void;\n onRequestProfilePicture: (phone: string) => void;\n}\n\nexport class CallWidget {\n private host: HTMLElement;\n private shadow: ShadowRoot;\n private root!: HTMLDivElement;\n private bubble!: HTMLDivElement;\n private badge!: HTMLSpanElement;\n private connDot!: HTMLSpanElement;\n private panel!: HTMLDivElement;\n private config: CallWidgetConfig;\n private open = false;\n private muted = false;\n private timers = new Map<string, ReturnType<typeof setInterval>>();\n private timerStarts = new Map<string, number>();\n\n // Views\n private currentView: ViewName = 'dialer';\n private dialerView!: HTMLDivElement;\n private callsView!: HTMLDivElement;\n private contactsView!: HTMLDivElement;\n private incallView!: HTMLDivElement;\n private dialerInput!: HTMLInputElement;\n private tabDialer!: HTMLButtonElement;\n private tabCalls!: HTMLButtonElement;\n private tabContacts!: HTMLButtonElement;\n private contactsLoaded = false;\n private contactsCache: ContactInfo[] = [];\n private pictureCache = new Map<string, string | null>();\n private pictureRequested = new Set<string>();\n\n // In-call state\n private incallTimerEl!: HTMLElement;\n private incallPhoneEl!: HTMLElement;\n private incallStateEl!: HTMLElement;\n private incallMuteBtn!: HTMLButtonElement;\n private audioLevelBar!: HTMLElement;\n private activeCallId: string | null = null;\n private cameraOn = false;\n\n // Video elements\n private remoteVideoCanvas!: HTMLCanvasElement;\n private videoContainer!: HTMLDivElement;\n private videoPhoneEl!: HTMLElement;\n private videoTimerEl!: HTMLElement;\n\n constructor(config: CallWidgetConfig) {\n this.config = config;\n\n this.host = document.createElement('div');\n this.host.id = 'zapi-call-widget';\n this.shadow = this.host.attachShadow({ mode: 'closed' });\n\n const style = document.createElement('style');\n style.textContent = buildCSS(config.theme);\n this.shadow.appendChild(style);\n\n this.buildDOM();\n document.body.appendChild(this.host);\n }\n\n private buildDOM(): void {\n this.root = document.createElement('div');\n this.root.className = `zapi-call-root ${this.config.position}`;\n\n // Panel\n this.panel = document.createElement('div');\n this.panel.className = 'panel';\n\n // Header with tabs\n const header = document.createElement('div');\n header.className = 'panel-header';\n header.innerHTML = `\n <div class=\"panel-header-top\">\n <h3>Telefone</h3>\n <button class=\"close-btn\">${ICON_CLOSE}</button>\n </div>\n <div class=\"tabs\">\n <button class=\"tab active\" data-tab=\"dialer\">${ICON_DIALPAD} Discador</button>\n <button class=\"tab\" data-tab=\"calls\">${ICON_CALL_LIST} Chamadas</button>\n <button class=\"tab\" data-tab=\"contacts\">${ICON_CONTACTS} Contatos</button>\n </div>\n `;\n header.querySelector('.close-btn')!.addEventListener('click', () => this.togglePanel(false));\n\n this.tabDialer = header.querySelector('[data-tab=\"dialer\"]')!;\n this.tabCalls = header.querySelector('[data-tab=\"calls\"]')!;\n this.tabContacts = header.querySelector('[data-tab=\"contacts\"]')!;\n this.tabDialer.addEventListener('click', () => this.switchView('dialer'));\n this.tabCalls.addEventListener('click', () => this.switchView('calls'));\n this.tabContacts.addEventListener('click', () => this.switchView('contacts'));\n\n this.panel.appendChild(header);\n\n // Panel body\n const body = document.createElement('div');\n body.className = 'panel-body';\n\n // Dialer view\n this.dialerView = document.createElement('div');\n this.dialerView.className = 'view active';\n this.buildDialerView();\n body.appendChild(this.dialerView);\n\n // Calls view\n this.callsView = document.createElement('div');\n this.callsView.className = 'view';\n this.callsView.innerHTML = `\n <div class=\"calls-view\">\n <div class=\"empty-state\">\n <div class=\"icon\">&#128222;</div>\n <p>Nenhuma chamada ativa</p>\n </div>\n </div>\n `;\n body.appendChild(this.callsView);\n\n // Contacts view\n this.contactsView = document.createElement('div');\n this.contactsView.className = 'view';\n this.buildContactsView();\n body.appendChild(this.contactsView);\n\n // In-call view\n this.incallView = document.createElement('div');\n this.incallView.className = 'view';\n this.buildInCallView();\n body.appendChild(this.incallView);\n\n this.panel.appendChild(body);\n this.root.appendChild(this.panel);\n\n // Bubble\n this.bubble = document.createElement('div');\n this.bubble.className = 'bubble';\n this.bubble.innerHTML = `\n ${ICON_PHONE}\n <span class=\"badge\">0</span>\n <span class=\"conn-dot\"></span>\n `;\n this.badge = this.bubble.querySelector('.badge')!;\n this.connDot = this.bubble.querySelector('.conn-dot')!;\n this.bubble.addEventListener('click', () => {\n this.togglePanel();\n this.config.onResume();\n });\n this.root.appendChild(this.bubble);\n\n this.shadow.appendChild(this.root);\n }\n\n private buildDialerView(): void {\n const dialer = document.createElement('div');\n dialer.className = 'dialer';\n\n // Number display\n const display = document.createElement('div');\n display.className = 'dialer-display';\n\n this.dialerInput = document.createElement('input');\n this.dialerInput.className = 'dialer-input';\n this.dialerInput.type = 'tel';\n this.dialerInput.placeholder = 'Digite o numero';\n this.dialerInput.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') this.handleMakeCall();\n });\n\n const backspaceBtn = document.createElement('button');\n backspaceBtn.className = 'backspace-btn';\n backspaceBtn.innerHTML = ICON_BACKSPACE;\n backspaceBtn.addEventListener('click', () => {\n this.dialerInput.value = this.dialerInput.value.slice(0, -1);\n this.dialerInput.focus();\n });\n\n display.appendChild(this.dialerInput);\n display.appendChild(backspaceBtn);\n dialer.appendChild(display);\n\n // Numpad\n const numpad = document.createElement('div');\n numpad.className = 'numpad';\n\n for (const key of NUMPAD_KEYS) {\n const btn = document.createElement('button');\n btn.className = 'numpad-key';\n btn.innerHTML = `<span>${key.digit}</span>${key.sub ? `<span class=\"sub\">${key.sub}</span>` : ''}`;\n btn.addEventListener('click', () => {\n this.dialerInput.value += key.digit;\n this.dialerInput.focus();\n });\n numpad.appendChild(btn);\n }\n\n dialer.appendChild(numpad);\n\n // Call buttons\n const callBtns = document.createElement('div');\n callBtns.className = 'call-btns';\n\n const callBtn = document.createElement('button');\n callBtn.className = 'call-btn';\n callBtn.innerHTML = ICON_PHONE;\n callBtn.addEventListener('click', () => this.handleMakeCall(false));\n callBtns.appendChild(callBtn);\n\n if (this.config.showVideoDialButton) {\n const videoCallBtn = document.createElement('button');\n videoCallBtn.className = 'call-btn video-call-btn';\n videoCallBtn.innerHTML = ICON_VIDEO;\n videoCallBtn.addEventListener('click', () => this.handleMakeCall(true));\n callBtns.appendChild(videoCallBtn);\n }\n\n dialer.appendChild(callBtns);\n\n this.dialerView.appendChild(dialer);\n }\n\n private buildContactsView(): void {\n const wrapper = document.createElement('div');\n wrapper.className = 'contacts-wrapper';\n\n const searchRow = document.createElement('div');\n searchRow.className = 'contacts-search-row';\n searchRow.innerHTML = `\n <div class=\"contacts-search-input-wrap\">\n ${ICON_SEARCH}\n <input class=\"contacts-search-input\" type=\"text\" placeholder=\"Buscar contato...\" />\n </div>\n <button class=\"contacts-refresh-btn\">${ICON_REFRESH}</button>\n `;\n\n const searchInput = searchRow.querySelector('.contacts-search-input') as HTMLInputElement;\n searchInput.addEventListener('input', () => this.filterContacts(searchInput.value));\n\n const refreshBtn = searchRow.querySelector('.contacts-refresh-btn')!;\n refreshBtn.addEventListener('click', () => {\n this.contactsLoaded = false;\n this.loadContacts();\n });\n\n wrapper.appendChild(searchRow);\n\n const list = document.createElement('div');\n list.className = 'contacts-list';\n list.innerHTML = `<div class=\"empty-state\"><p>Clique na aba para carregar</p></div>`;\n wrapper.appendChild(list);\n\n this.contactsView.appendChild(wrapper);\n }\n\n private loadContacts(): void {\n const list = this.contactsView.querySelector('.contacts-list')!;\n list.innerHTML = `<div class=\"contacts-loading\"><div class=\"spinner\"></div><p>Carregando contatos...</p></div>`;\n this.config.onRequestContacts();\n }\n\n private filterContacts(query: string): void {\n const q = query.toLowerCase().trim();\n const list = this.contactsView.querySelector('.contacts-list')!;\n const filtered = q ? this.contactsCache.filter(c =>\n c.name.toLowerCase().includes(q) || c.phone.includes(q)\n ) : this.contactsCache;\n this.renderContactsList(list, filtered);\n }\n\n private renderContactsList(container: Element, contacts: ContactInfo[]): void {\n if (contacts.length === 0) {\n container.innerHTML = `<div class=\"empty-state\"><p>Nenhum contato encontrado</p></div>`;\n return;\n }\n container.innerHTML = '';\n for (const contact of contacts) {\n const item = document.createElement('div');\n item.className = 'contact-item';\n const initials = (contact.short || contact.name || '?').charAt(0).toUpperCase();\n item.innerHTML = `\n <div class=\"contact-avatar\">${contact.imgUrl ? `<img src=\"${contact.imgUrl}\" />` : `<span>${initials}</span>`}</div>\n <div class=\"contact-info\">\n <div class=\"contact-name\">${contact.name || contact.phone}</div>\n <div class=\"contact-phone\">${contact.phone}</div>\n </div>\n <button class=\"contact-call-btn\">${ICON_PHONE}</button>\n `;\n item.querySelector('.contact-call-btn')!.addEventListener('click', () => {\n const phone = contact.phone.replace(/[^0-9+]/g, '');\n this.config.onMakeCall(phone, false);\n });\n container.appendChild(item);\n }\n }\n\n updateContacts(contacts: ContactInfo[]): void {\n this.contactsCache = contacts;\n this.contactsLoaded = true;\n const list = this.contactsView.querySelector('.contacts-list');\n if (list) this.renderContactsList(list, contacts);\n }\n\n private buildInCallView(): void {\n const view = document.createElement('div');\n view.className = 'incall-view';\n\n view.innerHTML = `\n <div class=\"video-container\" style=\"display:none;\">\n <canvas class=\"remote-video\"></canvas>\n <div class=\"video-overlay-top\">\n <div class=\"video-caller-info\">\n <div class=\"video-phone\"></div>\n <div class=\"video-timer\">00:00</div>\n </div>\n </div>\n <div class=\"video-overlay-bottom\">\n <button class=\"incall-btn video-btn-mute\">${ICON_MIC}</button>\n <button class=\"incall-btn video-btn-camera\">${ICON_VIDEO_OFF}</button>\n <button class=\"incall-btn video-btn-end\">${ICON_PHONE_END}</button>\n </div>\n </div>\n <div class=\"audio-call-ui\">\n <div class=\"incall-avatar\">${ICON_USER}</div>\n <div class=\"incall-phone\"></div>\n <div class=\"incall-state\"></div>\n <div class=\"incall-timer\">00:00</div>\n <div class=\"audio-level-wrap\">\n <div class=\"audio-level-bar\"></div>\n </div>\n <div class=\"incall-controls\">\n <button class=\"incall-btn incall-btn-mute\">${ICON_MIC}</button>\n <button class=\"incall-btn incall-btn-camera\">${ICON_VIDEO_OFF}</button>\n <button class=\"incall-btn incall-btn-end\">${ICON_PHONE_END}</button>\n </div>\n </div>\n `;\n\n this.videoContainer = view.querySelector('.video-container')!;\n this.remoteVideoCanvas = view.querySelector('.remote-video')!;\n\n this.incallPhoneEl = view.querySelector('.incall-phone')!;\n this.incallStateEl = view.querySelector('.incall-state')!;\n this.incallTimerEl = view.querySelector('.incall-timer')!;\n this.audioLevelBar = view.querySelector('.audio-level-bar')!;\n\n // Video overlay elements (duplicated info for video mode)\n this.videoPhoneEl = view.querySelector('.video-phone')!;\n this.videoTimerEl = view.querySelector('.video-timer')!;\n\n // Audio call mute button\n this.incallMuteBtn = view.querySelector('.incall-btn-mute')!;\n this.incallMuteBtn.addEventListener('click', () => {\n this.muted = !this.muted;\n this.config.onMute(this.muted);\n this.updateMuteButtons();\n });\n\n // Video call mute button\n const videoMuteBtn = view.querySelector('.video-btn-mute')!;\n videoMuteBtn.addEventListener('click', () => {\n this.muted = !this.muted;\n this.config.onMute(this.muted);\n this.updateMuteButtons();\n });\n\n // Camera toggle buttons (audio UI + video overlay)\n const cameraBtns = view.querySelectorAll('.video-btn-camera, .incall-btn-camera');\n cameraBtns.forEach(btn => {\n btn.addEventListener('click', () => {\n this.cameraOn = !this.cameraOn;\n this.config.onCamera(this.cameraOn);\n this.updateCameraButton();\n });\n });\n\n // End buttons (audio + video)\n const endBtn = view.querySelector('.incall-btn-end')!;\n endBtn.addEventListener('click', () => {\n if (this.activeCallId) this.config.onReject(this.activeCallId);\n });\n const videoEndBtn = view.querySelector('.video-btn-end')!;\n videoEndBtn.addEventListener('click', () => {\n if (this.activeCallId) this.config.onReject(this.activeCallId);\n });\n\n this.incallView.appendChild(view);\n }\n\n private handleMakeCall(isVideo = false): void {\n const number = this.dialerInput.value.replace(/\\s/g, '');\n if (!number) return;\n this.config.onMakeCall(number, isVideo);\n console.log('[ZAPICall] makeCall from widget:', number, isVideo ? '(video)' : '(audio)');\n }\n\n private switchView(view: ViewName): void {\n this.currentView = view;\n\n this.dialerView.classList.toggle('active', view === 'dialer');\n this.callsView.classList.toggle('active', view === 'calls');\n this.contactsView.classList.toggle('active', view === 'contacts');\n this.incallView.classList.toggle('active', view === 'incall');\n\n this.tabDialer.classList.toggle('active', view === 'dialer');\n this.tabCalls.classList.toggle('active', view === 'calls');\n this.tabContacts.classList.toggle('active', view === 'contacts');\n\n if (view === 'contacts' && !this.contactsLoaded) {\n this.loadContacts();\n }\n }\n\n private togglePanel(force?: boolean): void {\n this.open = force !== undefined ? force : !this.open;\n this.panel.classList.toggle('open', this.open);\n }\n\n updateCalls(calls: CallInfo[], connected: boolean): void {\n // Update connection dot\n this.connDot.classList.toggle('connected', connected);\n\n const activeCalls = calls.filter(c => c.state !== 'ended');\n const ringingCalls = calls.filter(c => c.state === 'ringing' || c.state === 'preaccepted' || c.state === 'calling');\n const liveCall = calls.find(c => c.state === 'active')\n || calls.find(c => c.state === 'accepted')\n || calls.find(c => c.state === 'calling');\n\n // Badge\n if (activeCalls.length > 0) {\n this.badge.textContent = String(activeCalls.length);\n this.badge.classList.add('visible');\n } else {\n this.badge.classList.remove('visible');\n }\n\n // Bubble pulse for ringing\n this.bubble.classList.toggle('ringing', ringingCalls.length > 0);\n\n // Auto-open panel on incoming call\n if (ringingCalls.length > 0 && !this.open) {\n this.togglePanel(true);\n }\n\n // Auto-switch to in-call view when a call becomes active\n if (liveCall) {\n this.activeCallId = liveCall.callId;\n this.incallPhoneEl.textContent = liveCall.notify || formatPhone(liveCall.from);\n this.incallStateEl.textContent = this.stateLabel(liveCall.state);\n if (this.videoPhoneEl) this.videoPhoneEl.textContent = liveCall.notify || formatPhone(liveCall.from);\n\n const incallAvatar = this.incallView.querySelector('.incall-avatar') as HTMLElement | null;\n if (incallAvatar && incallAvatar.dataset.avatarPhone !== liveCall.from) {\n incallAvatar.dataset.avatarPhone = liveCall.from;\n incallAvatar.innerHTML = this.renderAvatar(liveCall.from);\n }\n\n if (liveCall.state === 'accepted' || liveCall.state === 'active') {\n if (!this.timerStarts.has(liveCall.callId)) {\n this.timerStarts.set(liveCall.callId, Date.now());\n }\n this.startInCallTimer(liveCall.callId);\n } else {\n this.stopInCallTimer();\n }\n\n if (this.currentView !== 'incall') {\n this.switchView('incall');\n }\n } else if (this.currentView === 'incall') {\n // No more live calls, switch back\n this.activeCallId = null;\n this.stopInCallTimer();\n if (ringingCalls.length > 0) {\n this.switchView('calls');\n } else {\n this.switchView('dialer');\n }\n }\n\n // Auto-switch to calls when incoming and not in-call\n if (ringingCalls.length > 0 && !liveCall && this.currentView === 'dialer') {\n this.switchView('calls');\n }\n\n // Render calls list\n this.renderCallsList(calls);\n }\n\n private renderCallsList(calls: CallInfo[]): void {\n const container = this.callsView.querySelector('.calls-view')!;\n\n if (calls.length === 0) {\n container.innerHTML = `\n <div class=\"empty-state\">\n <div class=\"icon\">&#128222;</div>\n <p>Nenhuma chamada ativa</p>\n </div>\n `;\n this.clearAllTimers();\n return;\n }\n\n container.innerHTML = '';\n for (const call of calls) {\n container.appendChild(this.buildCallCard(call));\n }\n }\n\n private buildCallCard(call: CallInfo): HTMLDivElement {\n const card = document.createElement('div');\n card.className = `call-card${call.state === 'ended' ? ' ended' : ''}`;\n card.dataset.callId = call.callId;\n\n const isRinging = call.state === 'ringing' || call.state === 'preaccepted';\n const isCalling = call.state === 'calling';\n const isActive = call.state === 'accepted' || call.state === 'active';\n\n card.innerHTML = `\n <div class=\"call-card-top\">\n <div class=\"avatar\" data-avatar-phone=\"${call.from}\">${this.renderAvatar(call.from)}</div>\n <div class=\"call-info\">\n ${call.notify ? `<div class=\"call-name\">${call.notify}</div>` : ''}\n <div class=\"call-phone\">${formatPhone(call.from)}</div>\n <div class=\"call-meta\">\n ${call.isVideo ? ICON_VIDEO : ICON_PHONE}\n <span>${call.isVideo ? 'Video' : 'Audio'}${call.isGroup ? ' (Grupo)' : ''}</span>\n </div>\n </div>\n <span class=\"state-badge ${call.state}\">${this.stateLabel(call.state)}</span>\n </div>\n ${isActive ? `<div class=\"timer\" data-timer=\"${call.callId}\">00:00</div>` : ''}\n ${isRinging ? `\n <div class=\"call-actions\">\n <button class=\"btn btn-accept\" data-accept=\"${call.callId}\">\n ${ICON_PHONE_ACCEPT} Aceitar\n </button>\n <button class=\"btn btn-reject\" data-reject=\"${call.callId}\">\n ${ICON_PHONE_END} Rejeitar\n </button>\n </div>\n ` : ''}\n ${isCalling || isActive ? `\n <div class=\"call-actions\">\n <button class=\"btn btn-reject\" data-reject=\"${call.callId}\" style=\"flex:1\">\n ${ICON_PHONE_END} Encerrar\n </button>\n </div>\n ` : ''}\n `;\n\n // Wire button events\n const acceptBtn = card.querySelector(`[data-accept=\"${call.callId}\"]`);\n acceptBtn?.addEventListener('click', () => {\n this.config.onAccept(call.callId);\n this.config.onResume();\n });\n\n const rejectBtns = card.querySelectorAll(`[data-reject=\"${call.callId}\"]`);\n rejectBtns.forEach(btn => btn.addEventListener('click', () => this.config.onReject(call.callId)));\n\n // Start timer for active calls in list view\n if (isActive) {\n if (!this.timerStarts.has(call.callId)) {\n this.timerStarts.set(call.callId, Date.now());\n }\n this.startTimer(call.callId, card);\n }\n\n if (call.state === 'ended') {\n this.stopTimer(call.callId);\n }\n\n return card;\n }\n\n private stateLabel(state: string): string {\n switch (state) {\n case 'ringing': return 'Chamando';\n case 'calling': return 'Ligando...';\n case 'preaccepted': return 'Conectando';\n case 'accepted': return 'Aceita';\n case 'active': return 'Ativa';\n case 'ended': return 'Encerrada';\n default: return state;\n }\n }\n\n // Timers for call cards in list view\n private startTimer(callId: string, card: HTMLDivElement): void {\n this.stopTimer(callId);\n const startTime = this.timerStarts.get(callId) || Date.now();\n const el = card.querySelector(`[data-timer=\"${callId}\"]`) as HTMLElement | null;\n if (!el) return;\n\n const update = () => {\n el.textContent = formatDuration(Date.now() - startTime);\n };\n update();\n this.timers.set(callId, setInterval(update, 1000));\n }\n\n private stopTimer(callId: string): void {\n const timer = this.timers.get(callId);\n if (timer) {\n clearInterval(timer);\n this.timers.delete(callId);\n }\n }\n\n // In-call view timer\n private incallTimer: ReturnType<typeof setInterval> | null = null;\n\n private startInCallTimer(callId: string): void {\n this.stopInCallTimer();\n const startTime = this.timerStarts.get(callId) || Date.now();\n const update = () => {\n const text = formatDuration(Date.now() - startTime);\n this.incallTimerEl.textContent = text;\n if (this.videoTimerEl) this.videoTimerEl.textContent = text;\n };\n update();\n this.incallTimer = setInterval(update, 1000);\n }\n\n private stopInCallTimer(): void {\n if (this.incallTimer) {\n clearInterval(this.incallTimer);\n this.incallTimer = null;\n }\n this.incallTimerEl.textContent = '00:00';\n }\n\n /** Show video container for video calls */\n showVideo(isVideo: boolean): void {\n if (!this.videoContainer) return;\n this.videoContainer.style.display = isVideo ? 'flex' : 'none';\n const audioUi = this.incallView.querySelector('.audio-call-ui') as HTMLElement;\n if (audioUi) audioUi.style.display = isVideo ? 'none' : '';\n // Sync info to video overlay\n if (isVideo) {\n this.videoPhoneEl.textContent = this.incallPhoneEl.textContent;\n this.videoTimerEl.textContent = this.incallTimerEl.textContent;\n }\n }\n\n getRemoteCanvas(): HTMLCanvasElement { return this.remoteVideoCanvas; }\n\n resetCamera(): void {\n this.cameraOn = false;\n this.updateCameraButton();\n }\n\n private updateMuteButtons(): void {\n this.incallMuteBtn.classList.toggle('muted', this.muted);\n this.incallMuteBtn.innerHTML = this.muted ? ICON_MIC_OFF : ICON_MIC;\n const vmb = this.incallView.querySelector('.video-btn-mute') as HTMLElement;\n if (vmb) {\n vmb.classList.toggle('muted', this.muted);\n vmb.innerHTML = this.muted ? ICON_MIC_OFF : ICON_MIC;\n }\n }\n\n private updateCameraButton(): void {\n const btns = this.incallView.querySelectorAll('.video-btn-camera, .incall-btn-camera');\n btns.forEach(btn => {\n btn.classList.toggle('muted', !this.cameraOn);\n btn.innerHTML = this.cameraOn ? ICON_VIDEO : ICON_VIDEO_OFF;\n });\n }\n\n showMakeCallError(reason: string): void {\n const msg = reason.includes('PHONE_NOT_ON_WHATSAPP')\n ? 'N\\u00famero n\\u00e3o encontrado'\n : 'Erro ao realizar chamada';\n const prev = this.dialerInput.placeholder;\n this.dialerInput.value = '';\n this.dialerInput.placeholder = msg;\n this.dialerInput.classList.add('error');\n setTimeout(() => {\n this.dialerInput.placeholder = prev;\n this.dialerInput.classList.remove('error');\n }, 3000);\n }\n\n updateAudioLevel(level: number): void {\n const pct = Math.min(100, Math.max(0, level * 100));\n this.audioLevelBar.style.width = `${pct}%`;\n }\n\n private renderAvatar(phone: string): string {\n const cached = this.pictureCache.get(phone);\n if (cached) return `<img src=\"${cached}\" class=\"avatar-img\" />`;\n if (!this.pictureRequested.has(phone) && phone) {\n this.pictureRequested.add(phone);\n this.config.onRequestProfilePicture(phone);\n }\n return ICON_USER;\n }\n\n updateProfilePicture(phone: string, url: string | null): void {\n this.pictureCache.set(phone, url);\n if (!url) return;\n\n const avatarHtml = `<img src=\"${url}\" class=\"avatar-img\" />`;\n this.shadow.querySelectorAll(`[data-avatar-phone=\"${phone}\"]`).forEach((el) => {\n el.innerHTML = avatarHtml;\n });\n }\n\n private clearAllTimers(): void {\n for (const timer of this.timers.values()) {\n clearInterval(timer);\n }\n this.timers.clear();\n this.timerStarts.clear();\n this.stopInCallTimer();\n }\n\n destroy(): void {\n this.clearAllTimers();\n this.host.remove();\n }\n}\n","import type {\n ZAPICallOptions,\n ZAPICallEvents,\n CallInfo,\n ContactInfo,\n WsServerMessage,\n AudioConfig,\n VideoFrameInfo,\n} from '../types';\nimport { EventEmitter } from './EventEmitter';\nimport { CallWebSocket } from './CallWebSocket';\nimport { AudioEngine } from './AudioEngine';\nimport { VideoEngine } from './VideoEngine';\nimport { CallStateManager } from './CallState';\nimport { CallWidget } from '../widget/CallWidget';\n\nexport class ZAPICallClient extends EventEmitter<ZAPICallEvents> {\n private ws: CallWebSocket;\n private audio: AudioEngine;\n private video: VideoEngine;\n private state: CallStateManager;\n private widget: CallWidget | null = null;\n private opts: ZAPICallOptions;\n private audioConfig: AudioConfig = { sampleRate: 16000, channels: 1 };\n private connected = false;\n private micStarted = false;\n private cameraStarted = false;\n private destroyed = false;\n private sdkId = '';\n private contacts: ContactInfo[] = [];\n\n constructor(opts: ZAPICallOptions) {\n super();\n this.opts = opts;\n\n this.state = new CallStateManager();\n this.audio = new AudioEngine(this.audioConfig.sampleRate);\n this.video = new VideoEngine();\n this.ws = new CallWebSocket(__BASE_URL__, opts.instanceId, opts.getToken);\n\n // Wire WS events\n this.ws.onJson = (msg) => this.handleJsonMessage(msg);\n this.ws.onBinary = (data) => this.handleBinaryMessage(data);\n this.ws.onConnectionChange = (c) => this.handleConnectionChange(c);\n\n // Wire audio mic → WS\n this.audio.onMicData = (pcm) => {\n const framed = new ArrayBuffer(1 + pcm.byteLength);\n new Uint8Array(framed)[0] = 0x01;\n new Uint8Array(framed, 1).set(new Uint8Array(pcm));\n this.ws.send(framed);\n };\n this.audio.onAudioLevel = (level) => {\n this.emit('audio:level', level);\n this.widget?.updateAudioLevel(level);\n };\n\n // Wire video rendering\n this.on('video:frame', (frame) => this.video.renderFrame(frame));\n\n this.video.onEncodedCameraFrame = (h264, w, h, tsSec, isKey, latencyMs) => {\n const packet = new ArrayBuffer(22 + h264.byteLength);\n const view = new DataView(packet);\n view.setUint8(0, 0x03);\n view.setUint16(1, w, true);\n view.setUint16(3, h, true);\n view.setFloat64(5, tsSec);\n view.setUint8(13, isKey ? 1 : 0);\n view.setFloat64(14, latencyMs);\n new Uint8Array(packet, 22).set(new Uint8Array(h264));\n this.ws.send(packet);\n };\n\n this.video.onCameraFrame = (rgba, w, h) => {\n const nv12 = this.rgbaToNv12(new Uint8Array(rgba), w, h);\n const packet = new ArrayBuffer(5 + nv12.byteLength);\n const view = new DataView(packet);\n view.setUint8(0, 0x02);\n view.setUint16(1, w, true);\n view.setUint16(3, h, true);\n new Uint8Array(packet, 5).set(nv12);\n this.ws.send(packet);\n };\n\n // Create widget if enabled\n if (opts.autoWidget !== false) {\n this.widget = new CallWidget({\n position: opts.position || 'bottom-right',\n theme: opts.theme || {},\n showVideoDialButton: opts.showVideoDialButton === true,\n onAccept: (callId) => this.accept(callId),\n onReject: (callId) => this.reject(callId),\n onMute: (muted) => this.mute(muted),\n onCamera: (enabled) => this.setCamera(enabled),\n onResume: () => this.audio.resume(),\n onMakeCall: (number, isVideo) => this.makeCall(number, isVideo),\n onRequestContacts: () => this.requestContacts(),\n onRequestProfilePicture: (phone: string) => this.requestProfilePicture(phone),\n });\n\n // Attach video engine to widget canvas\n this.video.setRemoteCanvas(this.widget.getRemoteCanvas());\n }\n\n this.ws.connect();\n }\n\n // -- Public API --\n\n accept(callId: string): void {\n console.log('[ZAPICall] >> call:accept', callId);\n this.ws.sendJson({ type: 'call:accept', callId });\n this.startMicIfNeeded();\n }\n\n reject(callId: string): void {\n console.log('[ZAPICall] >> call:reject', callId);\n this.ws.sendJson({ type: 'call:reject', callId });\n }\n\n mute(muted: boolean): void {\n this.ws.sendJson({ type: 'call:mute', muted });\n }\n\n async setCamera(enabled: boolean): Promise<void> {\n this.ws.sendJson({ type: 'call:camera', enabled });\n if (enabled) {\n await this.startCameraIfNeeded();\n this.widget?.showVideo(true);\n } else {\n this.video.stopCamera();\n this.cameraStarted = false;\n }\n }\n\n isCameraActive(): boolean {\n return this.cameraStarted;\n }\n\n makeCall(number: string, isVideo = false): void {\n console.log('[ZAPICall] >> call:make', number, isVideo ? '(video)' : '(audio)');\n this.audio.resume();\n this.ws.sendJson({ type: 'call:make', number, isVideo });\n this.emit('call:make', number);\n this.opts.onMakeCall?.(number);\n }\n\n getCalls(): CallInfo[] {\n return this.state.getAllCalls();\n }\n\n getActiveCall(): CallInfo | undefined {\n return this.state.getActiveCall();\n }\n\n isConnected(): boolean {\n return this.connected;\n }\n\n getSdkId(): string {\n return this.sdkId;\n }\n\n requestContacts(): void {\n this.ws.sendJson({ type: 'contacts:list' });\n }\n\n requestProfilePicture(phone: string): void {\n this.ws.sendJson({ type: 'profile:picture', phone });\n }\n\n getContacts(): ContactInfo[] {\n return this.contacts;\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.ws.destroy();\n this.audio.destroy();\n this.video.destroy();\n this.widget?.destroy();\n this.state.clear();\n this.removeAllListeners();\n }\n\n // -- Internal --\n\n private handleJsonMessage(msg: WsServerMessage): void {\n switch (msg.type) {\n case 'connected':\n this.sdkId = msg.sdkId || '';\n if (msg.audioConfig) {\n // Recreate audio engine if sample rate changed\n if (msg.audioConfig.sampleRate !== this.audioConfig.sampleRate) {\n this.audio.destroy();\n this.audio = new AudioEngine(msg.audioConfig.sampleRate);\n this.audio.onMicData = (pcm) => {\n const framed = new ArrayBuffer(1 + pcm.byteLength);\n new Uint8Array(framed)[0] = 0x01;\n new Uint8Array(framed, 1).set(new Uint8Array(pcm));\n this.ws.send(framed);\n };\n this.audio.onAudioLevel = (level) => {\n this.emit('audio:level', level);\n this.widget?.updateAudioLevel(level);\n };\n }\n this.audioConfig = msg.audioConfig;\n }\n break;\n\n case 'call:incoming': {\n const call: CallInfo = {\n callId: msg.callId,\n from: msg.from,\n notify: msg.notify,\n isVideo: msg.isVideo,\n isGroup: msg.isGroup,\n state: msg.state || 'ringing',\n timestamp: msg.timestamp,\n };\n this.state.addCall(call);\n this.emit('call:incoming', call);\n this.opts.onIncomingCall?.(call);\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n break;\n }\n\n case 'call:outgoing': {\n const outCall: CallInfo = {\n callId: msg.callId,\n from: msg.to,\n isVideo: msg.isVideo,\n isGroup: false,\n state: 'calling',\n timestamp: Date.now(),\n };\n this.state.addCall(outCall);\n this.emit('call:outgoing', outCall);\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n this.startMicIfNeeded();\n break;\n }\n\n case 'call:state': {\n if (!this.state.getCall(msg.callId)) break;\n this.state.updateState(msg.callId, msg.state);\n this.emit('call:state', msg.callId, msg.state);\n\n if (msg.state === 'accepted' || msg.state === 'active') {\n this.startMicIfNeeded();\n\n const call = this.state.getCall(msg.callId);\n if (call?.isVideo) {\n this.widget?.showVideo(true);\n this.startCameraIfNeeded();\n } else {\n this.video.stopCamera();\n this.cameraStarted = false;\n this.widget?.showVideo(false);\n }\n }\n\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n break;\n }\n\n case 'call:terminated': {\n this.state.updateState(msg.callId, 'ended');\n this.emit('call:terminated', msg.callId, msg.reason);\n this.opts.onCallTerminated?.(msg.callId);\n\n this.video.stopCamera();\n this.video.clearCanvas();\n this.cameraStarted = false;\n this.widget?.showVideo(false);\n this.widget?.resetCamera();\n\n setTimeout(() => {\n this.state.removeCall(msg.callId);\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n\n if (!this.state.hasActiveCalls()) {\n this.audio.stopMic();\n this.micStarted = false;\n }\n }, 3000);\n\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n break;\n }\n\n case 'call:video-state': {\n this.state.updateIsVideo(msg.callId, msg.isVideo);\n this.emit('call:video-state', msg.callId, msg.isVideo);\n\n const vCall = this.state.getCall(msg.callId);\n if (vCall && (vCall.state === 'accepted' || vCall.state === 'active')) {\n if (msg.isVideo) {\n this.widget?.showVideo(true);\n } else {\n this.video.stopCamera();\n this.cameraStarted = false;\n this.widget?.showVideo(false);\n }\n }\n\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n break;\n }\n\n case 'call:claimed': {\n this.state.removeCall(msg.callId);\n this.emit('call:claimed', msg.callId);\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n break;\n }\n\n case 'call:dismissed': {\n this.state.removeCall(msg.callId);\n this.emit('call:dismissed', msg.callId);\n this.widget?.updateCalls(this.state.getAllCalls(), this.connected);\n break;\n }\n\n case 'contacts:list': {\n this.contacts = msg.contacts || [];\n this.emit('contacts:list', this.contacts);\n this.widget?.updateContacts(this.contacts);\n break;\n }\n\n case 'profile:picture': {\n this.emit('profile:picture', msg.phone, msg.url);\n this.widget?.updateProfilePicture(msg.phone, msg.url);\n break;\n }\n\n case 'pong':\n break;\n\n case 'error':\n if (msg.command === 'call:make') {\n this.emit('call:make:error', '', msg.message || 'UNKNOWN_ERROR');\n this.widget?.showMakeCallError(msg.message || 'UNKNOWN_ERROR');\n }\n this.emit('error', new Error(`${msg.command}: ${msg.message}`));\n break;\n }\n }\n\n private handleBinaryMessage(data: ArrayBuffer): void {\n if (data.byteLength < 2) return;\n const view = new DataView(data);\n const firstByte = view.getUint8(0);\n\n // Video frame: prefix 0x01 + 15 bytes header + pixel data (always >= 16 bytes)\n if (firstByte === 0x01 && data.byteLength >= 16) {\n const width = view.getUint16(1, true);\n const height = view.getUint16(3, true);\n const format = view.getUint8(5);\n const orientation = view.getUint8(6);\n const isKeyFrame = view.getUint8(7) !== 0;\n const timestamp = view.getFloat64(8, false);\n const frameData = data.slice(16);\n\n const frame: VideoFrameInfo = {\n width, height, format, orientation,\n isKeyFrame, timestamp, data: frameData,\n };\n this.emit('video:frame', frame);\n return;\n }\n\n // Audio: prefix 0x00 + PCM data (odd total length since PCM is always even)\n if (firstByte === 0x00 && data.byteLength % 2 === 1) {\n this.audio.playPcm(data.slice(1));\n return;\n }\n\n // Legacy/fallback: raw PCM Int16LE (even length, no prefix)\n this.audio.playPcm(data);\n }\n\n private handleConnectionChange(connected: boolean): void {\n this.connected = connected;\n if (connected) {\n this.emit('connected');\n } else {\n this.emit('disconnected');\n }\n this.opts.onConnectionChange?.(connected);\n this.widget?.updateCalls(this.state.getAllCalls(), connected);\n }\n\n private async startCameraIfNeeded(): Promise<void> {\n if (this.cameraStarted || this.destroyed) return;\n this.cameraStarted = true;\n try {\n const videoEl = document.createElement('video');\n videoEl.style.display = 'none';\n document.body.appendChild(videoEl);\n await this.video.startCamera(videoEl, 320, 240, 30);\n } catch (e) {\n console.warn('[ZAPICall] Camera start failed:', e);\n this.cameraStarted = false;\n }\n }\n\n private rgbaToNv12(rgba: Uint8Array, w: number, h: number): Uint8Array {\n const ySize = w * h;\n const nv12 = new Uint8Array(ySize + (ySize >> 1));\n // Y plane\n for (let j = 0; j < h; j++) {\n for (let i = 0; i < w; i++) {\n const idx = (j * w + i) * 4;\n nv12[j * w + i] = ((66 * rgba[idx] + 129 * rgba[idx + 1] + 25 * rgba[idx + 2] + 128) >> 8) + 16;\n }\n }\n // UV plane (NV12 interleaved)\n let uvOff = ySize;\n for (let j = 0; j < h; j += 2) {\n for (let i = 0; i < w; i += 2) {\n const idx = (j * w + i) * 4;\n nv12[uvOff++] = ((-38 * rgba[idx] - 74 * rgba[idx + 1] + 112 * rgba[idx + 2] + 128) >> 8) + 128;\n nv12[uvOff++] = ((112 * rgba[idx] - 94 * rgba[idx + 1] - 18 * rgba[idx + 2] + 128) >> 8) + 128;\n }\n }\n return nv12;\n }\n\n private async startMicIfNeeded(): Promise<void> {\n if (this.micStarted || this.destroyed) return;\n this.micStarted = true;\n try {\n await this.audio.startMic();\n } catch (e) {\n this.emit('error', e instanceof Error ? e : new Error(String(e)));\n }\n }\n\n}\n","export type ThemeMode = 'dark' | 'light';\n\nexport interface ZAPICallTheme {\n mode?: ThemeMode;\n primaryColor?: string;\n dangerColor?: string;\n backgroundColor?: string;\n surfaceColor?: string;\n textColor?: string;\n textSecondaryColor?: string;\n borderRadius?: string;\n fontFamily?: string;\n}\n\nexport type WidgetPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n\nexport interface ZAPICallOptions {\n instanceId: string;\n getToken: () => Promise<string>;\n autoWidget?: boolean;\n showVideoDialButton?: boolean;\n position?: WidgetPosition;\n theme?: ZAPICallTheme;\n onIncomingCall?: (call: CallInfo) => void;\n onCallTerminated?: (callId: string) => void;\n onConnectionChange?: (connected: boolean) => void;\n onMakeCall?: (number: string) => void;\n}\n\nexport type CallState = 'ringing' | 'calling' | 'preaccepted' | 'accepted' | 'active' | 'ended';\n\nexport interface CallInfo {\n callId: string;\n from: string;\n notify?: string;\n isVideo: boolean;\n isGroup: boolean;\n state: CallState;\n timestamp: number;\n}\n\nexport interface AudioConfig {\n sampleRate: number;\n channels: number;\n}\n\nexport const VideoFormat = { NV12: 0, I420: 1, RGB24: 2, RGBA: 3, H264: 100 } as const;\nexport const VideoOrientation = { Unknown: 0, Normal: 1, Rotate90: 2, Rotate180: 3, Rotate270: 4 } as const;\n\nexport interface VideoFrameInfo {\n width: number;\n height: number;\n format: number;\n orientation: number;\n isKeyFrame: boolean;\n timestamp: number;\n data: ArrayBuffer;\n}\n\n// WebSocket protocol messages (server → client)\nexport interface WsConnectedMsg {\n type: 'connected';\n instanceId: string;\n sdkId: string;\n audioConfig: AudioConfig;\n}\n\nexport interface WsCallIncomingMsg {\n type: 'call:incoming';\n callId: string;\n from: string;\n notify?: string;\n isVideo: boolean;\n isGroup: boolean;\n state?: CallState;\n timestamp: number;\n}\n\nexport interface WsCallStateMsg {\n type: 'call:state';\n callId: string;\n state: CallState;\n}\n\nexport interface WsCallTerminatedMsg {\n type: 'call:terminated';\n callId: string;\n reason?: string;\n}\n\nexport interface WsPongMsg {\n type: 'pong';\n ts: number;\n}\n\nexport interface WsCallMakeMsg {\n type: 'call:make';\n number: string;\n}\n\nexport interface WsCallOutgoingMsg {\n type: 'call:outgoing';\n callId: string;\n to: string;\n isVideo: boolean;\n}\n\nexport interface WsErrorMsg {\n type: 'error';\n command: string;\n message: string;\n}\n\nexport interface WsCallClaimedMsg {\n type: 'call:claimed';\n callId: string;\n}\n\nexport interface WsCallDismissedMsg {\n type: 'call:dismissed';\n callId: string;\n}\n\nexport interface WsCallVideoStateMsg {\n type: 'call:video-state';\n callId: string;\n isVideo: boolean;\n}\n\nexport interface ContactInfo {\n name: string;\n phone: string;\n short: string;\n imgUrl: string | null;\n}\n\nexport interface WsContactsListMsg {\n type: 'contacts:list';\n contacts: ContactInfo[];\n}\n\nexport interface WsProfilePictureMsg {\n type: 'profile:picture';\n phone: string;\n url: string | null;\n}\n\nexport type WsServerMessage =\n | WsConnectedMsg\n | WsCallIncomingMsg\n | WsCallOutgoingMsg\n | WsCallStateMsg\n | WsCallTerminatedMsg\n | WsCallClaimedMsg\n | WsCallDismissedMsg\n | WsCallVideoStateMsg\n | WsContactsListMsg\n | WsProfilePictureMsg\n | WsPongMsg\n | WsErrorMsg;\n\n// Events emitted by ZAPICallClient\nexport interface ZAPICallEvents {\n 'connected': () => void;\n 'disconnected': () => void;\n 'call:incoming': (call: CallInfo) => void;\n 'call:state': (callId: string, state: CallState) => void;\n 'call:terminated': (callId: string, reason?: string) => void;\n 'call:claimed': (callId: string) => void;\n 'call:dismissed': (callId: string) => void;\n 'call:video-state': (callId: string, isVideo: boolean) => void;\n 'contacts:list': (contacts: ContactInfo[]) => void;\n 'call:make': (number: string) => void;\n 'call:outgoing': (call: CallInfo) => void;\n 'audio:level': (level: number) => void;\n 'video:frame': (frame: VideoFrameInfo) => void;\n 'call:make:error': (number: string, reason: string) => void;\n 'profile:picture': (phone: string, url: string | null) => void;\n 'error': (error: Error) => void;\n}\n","import { ZAPICallClient } from './core/ZAPICallClient';\nimport type { ZAPICallOptions } from './types';\n\n// Re-export types for TypeScript consumers\nexport type {\n ZAPICallOptions,\n ZAPICallTheme,\n ThemeMode,\n WidgetPosition,\n CallState,\n CallInfo,\n AudioConfig,\n VideoFrameInfo,\n ZAPICallEvents,\n WsCallMakeMsg,\n} from './types';\n\nexport { VideoFormat, VideoOrientation } from './types';\n\n// Re-export class for advanced usage\nexport { ZAPICallClient } from './core/ZAPICallClient';\n\n/**\n * Initialize the SDK. Creates a WebSocket connection, optional widget,\n * and returns a client for controlling calls.\n *\n * @example\n * ```ts\n * // ESM\n * import { init } from '@z-api/call';\n * const client = init({ instanceId: '123', getToken: async () => 'abc' });\n *\n * // or via namespace\n * import { ZAPICall } from '@z-api/call';\n * const client = ZAPICall.init({ instanceId: '123', getToken: async () => 'abc' });\n *\n * // Script tag\n * // <script src=\"z-api-call.global.js\"></script>\n * // const client = ZAPICall.init({ instanceId: '123', getToken: async () => 'abc' });\n * ```\n */\nexport function init(opts: ZAPICallOptions): ZAPICallClient {\n return new ZAPICallClient(opts);\n}\n\n/** Namespace object for convenience. */\nexport const ZAPICall = {\n init,\n Client: ZAPICallClient,\n};\n"],"names":["EventEmitter","event","listener","_a","args","set","e","INITIAL_RECONNECT_MS","MAX_RECONNECT_MS","PING_INTERVAL_MS","CallWebSocket","baseUrl","instanceId","getToken","token","u","url","ws","parsed","data","msg","int16ToFloat32","int16","float32","i","float32ToInt16","s","calculateRmsLevel","samples","sum","SCHEDULE_AHEAD_S","MAX_QUEUE_S","AudioEngine","sampleRate","int16Preview","maxVal","abs","level","buffer","source","now","track","H264_FORMAT","H264_CODEC","MAX_DECODER_ERRORS","VideoEngine","canvas","frame","width","height","orientation","format","isKeyFrame","timestamp","_width","_height","tsUs","decoder","vf","w","h","isRotated","displayW","displayH","nv12","rgba","imgData","videoEl","fps","stream","encodeW","encodeH","frameCount","submitTimes","chunk","meta","buf","isKey","codedW","codedH","_b","latencyMs","submitted","tsSec","reader","done","sinceLastKey","needKey","yPlaneSize","j","yIdx","uvIdx","y","v","rgbaIdx","clamp","CallStateManager","call","callId","state","isVideo","result","buildCSS","theme","light","primary","danger","bg","surface","text","textSec","radius","font","overlay","overlayHover","overlayActive","shadow","shadowLg","border","borderLight","ICON_PHONE","ICON_PHONE_END","ICON_PHONE_ACCEPT","ICON_MIC","ICON_MIC_OFF","ICON_USER","ICON_VIDEO","ICON_VIDEO_OFF","ICON_CLOSE","ICON_BACKSPACE","ICON_DIALPAD","ICON_CALL_LIST","ICON_CONTACTS","ICON_SEARCH","ICON_REFRESH","formatDuration","ms","totalSec","min","sec","formatPhone","phone","digits","NUMPAD_KEYS","CallWidget","config","style","header","body","dialer","display","backspaceBtn","numpad","key","btn","callBtns","callBtn","videoCallBtn","wrapper","searchRow","searchInput","list","query","q","filtered","c","container","contacts","contact","item","initials","view","number","force","calls","connected","activeCalls","ringingCalls","liveCall","incallAvatar","card","isRinging","isCalling","isActive","acceptBtn","startTime","el","update","timer","audioUi","vmb","reason","prev","pct","cached","avatarHtml","ZAPICallClient","opts","pcm","framed","h264","packet","muted","enabled","_c","outCall","_d","_e","_f","_g","_i","_h","_j","_k","_l","vCall","_m","_n","_o","_p","_q","_r","_s","_t","firstByte","frameData","ySize","idx","uvOff","VideoFormat","VideoOrientation","init","ZAPICall"],"mappings":"uCAEO,MAAMA,CAA+D,CAArE,aAAA,CACL,KAAQ,cAAgB,GAAiC,CAEzD,GAA2BC,EAAUC,EAA2B,CAC9D,OAAK,KAAK,UAAU,IAAID,CAAK,GAC3B,KAAK,UAAU,IAAIA,EAAO,IAAI,GAAK,EAErC,KAAK,UAAU,IAAIA,CAAK,EAAG,IAAIC,CAAoB,EAC5C,IACT,CAEA,IAA4BD,EAAUC,EAA2B,OAC/D,OAAAC,EAAA,KAAK,UAAU,IAAIF,CAAK,IAAxB,MAAAE,EAA2B,OAAOD,GAC3B,IACT,CAEU,KAA6BD,KAAaG,EAAmC,CACrF,MAAMC,EAAM,KAAK,UAAU,IAAIJ,CAAK,EACpC,GAAKI,EACL,UAAWH,KAAYG,EACrB,GAAI,CACFH,EAAS,GAAGE,CAAI,CAClB,OAASE,EAAG,CACV,QAAQ,MAAM,oCAAoC,OAAOL,CAAK,CAAC,KAAMK,CAAC,CACxE,CAEJ,CAEA,oBAA2B,CACzB,KAAK,UAAU,MAAA,CACjB,CACF,CC3BA,MAAMC,EAAuB,IACvBC,EAAmB,IACnBC,EAAmB,KAElB,MAAMC,CAAc,CAczB,YAAYC,EAAiBC,EAAoBC,EAAiC,CAblF,KAAQ,GAAuB,KAI/B,KAAQ,YAAcN,EACtB,KAAQ,eAAuD,KAC/D,KAAQ,UAAmD,KAC3D,KAAQ,UAAY,GAEpB,KAAA,OAAwB,IAAM,CAAC,EAC/B,KAAA,SAA4B,IAAM,CAAC,EACnC,KAAA,mBAAyC,IAAM,CAAC,EAG9C,KAAK,QAAUI,EACf,KAAK,WAAaC,EAClB,KAAK,SAAWC,CAClB,CAEQ,SAASC,EAAuB,CACtC,MAAMC,EAAI,IAAI,IAAI,KAAK,OAAO,EAC9B,OAAAA,EAAE,SAAWA,EAAE,WAAa,SAAW,OAAS,MAChDA,EAAE,SAAW,WACbA,EAAE,aAAa,IAAI,WAAY,KAAK,UAAU,EAC9CA,EAAE,aAAa,IAAI,QAASD,CAAK,EAC1BC,EAAE,SAAA,CACX,CAEA,MAAM,SAAyB,CAC7B,GAAI,KAAK,UAAW,OACpB,KAAK,QAAA,EAEL,IAAID,EACJ,GAAI,CACFA,EAAQ,MAAM,KAAK,SAAA,CACrB,OAASR,EAAG,CACV,QAAQ,KAAK,kCAAmCA,CAAC,EACjD,KAAK,kBAAA,EACL,MACF,CAEA,GAAI,KAAK,UAAW,OAEpB,MAAMU,EAAM,KAAK,SAASF,CAAK,EAC/B,QAAQ,IAAI,2BAA4BE,CAAG,EAE3C,MAAMC,EAAK,IAAI,UAAUD,CAAG,EAC5BC,EAAG,WAAa,cAChB,KAAK,GAAKA,EAEVA,EAAG,OAAS,IAAM,CAChB,QAAQ,IAAI,gCAAgC,EAC5C,KAAK,YAAcV,EACnB,KAAK,mBAAmB,EAAI,EAC5B,KAAK,UAAA,CACP,EAEAU,EAAG,UAAahB,GAAU,CACxB,GAAI,OAAOA,EAAM,MAAS,SACxB,GAAI,CACF,MAAMiB,EAAS,KAAK,MAAMjB,EAAM,IAAI,EACpC,QAAQ,IAAI,gBAAiBiB,EAAO,KAAMA,CAAM,EAChD,KAAK,OAAOA,CAAM,CACpB,MAAQ,CAAC,MACAjB,EAAM,gBAAgB,aAC/B,KAAK,SAASA,EAAM,IAAI,CAE5B,EAEAgB,EAAG,QAAWhB,GAAU,CAItB,GAHA,QAAQ,IAAI,+BAAgCA,EAAM,KAAMA,EAAM,MAAM,EACpE,KAAK,SAAA,EACL,KAAK,mBAAmB,EAAK,EACzBA,EAAM,OAAS,KAAM,CACvB,QAAQ,KAAK,yDAAyD,EACtE,MACF,CACA,KAAK,kBAAA,CACP,EAEAgB,EAAG,QAAWhB,GAAU,CACtB,QAAQ,KAAK,8BAA+BA,CAAK,CACnD,CACF,CAEA,KAAKkB,EAAkC,SACjChB,EAAA,KAAK,KAAL,YAAAA,EAAS,cAAe,UAAU,MACpC,KAAK,GAAG,KAAKgB,CAAI,CAErB,CAEA,SAASC,EAAoC,CAC3C,KAAK,KAAK,KAAK,UAAUA,CAAG,CAAC,CAC/B,CAEA,aAAuB,OACrB,QAAOjB,EAAA,KAAK,KAAL,YAAAA,EAAS,cAAe,UAAU,IAC3C,CAEA,SAAgB,CACd,KAAK,UAAY,GACjB,KAAK,QAAA,EACD,KAAK,iBACP,aAAa,KAAK,cAAc,EAChC,KAAK,eAAiB,KAE1B,CAEQ,SAAgB,CACtB,KAAK,SAAA,EACD,KAAK,KACP,KAAK,GAAG,OAAS,KACjB,KAAK,GAAG,UAAY,KACpB,KAAK,GAAG,QAAU,KAClB,KAAK,GAAG,QAAU,MACd,KAAK,GAAG,aAAe,UAAU,MAAQ,KAAK,GAAG,aAAe,UAAU,aAC5E,KAAK,GAAG,MAAA,EAEV,KAAK,GAAK,KAEd,CAEQ,mBAA0B,CAC5B,KAAK,YACT,KAAK,eAAiB,WAAW,IAAM,CACrC,KAAK,QAAA,CACP,EAAG,KAAK,WAAW,EACnB,KAAK,YAAc,KAAK,IAAI,KAAK,YAAc,EAAGK,CAAgB,EACpE,CAEQ,WAAkB,CACxB,KAAK,UAAY,YAAY,IAAM,CACjC,KAAK,SAAS,CAAE,KAAM,MAAA,CAAQ,CAChC,EAAGC,CAAgB,CACrB,CAEQ,UAAiB,CACnB,KAAK,YACP,cAAc,KAAK,SAAS,EAC5B,KAAK,UAAY,KAErB,CACF,CCxJO,SAASY,EAAeC,EAAiC,CAC9D,MAAMC,EAAU,IAAI,aAAaD,EAAM,MAAM,EAC7C,QAASE,EAAI,EAAGA,EAAIF,EAAM,OAAQE,IAChCD,EAAQC,CAAC,EAAIF,EAAME,CAAC,EAAI,MAE1B,OAAOD,CACT,CAGO,SAASE,EAAeF,EAAmC,CAChE,MAAMD,EAAQ,IAAI,WAAWC,EAAQ,MAAM,EAC3C,QAASC,EAAI,EAAGA,EAAID,EAAQ,OAAQC,IAAK,CACvC,IAAIE,EAAIH,EAAQC,CAAC,EACbE,EAAI,EAAGA,EAAI,EACNA,EAAI,KAAIA,EAAI,IACrBJ,EAAME,CAAC,EAAI,KAAK,MAAME,EAAI,KAAK,CACjC,CACA,OAAOJ,CACT,CAGO,SAASK,EAAkBC,EAA+B,CAC/D,GAAIA,EAAQ,SAAW,EAAG,MAAO,GACjC,IAAIC,EAAM,EACV,QAASL,EAAI,EAAGA,EAAII,EAAQ,OAAQJ,IAClCK,GAAOD,EAAQJ,CAAC,EAAII,EAAQJ,CAAC,EAE/B,OAAO,KAAK,KAAKK,EAAMD,EAAQ,MAAM,CACvC,CC3BA,MAAME,EAAmB,IACnBC,EAAc,IAKb,MAAMC,CAAY,CAavB,YAAYC,EAAa,KAAO,CAZhC,KAAQ,YAAmC,KAC3C,KAAQ,OAA8B,KACtC,KAAQ,UAAgC,KACxC,KAAQ,aAA2C,KACnD,KAAQ,UAA+C,KACvD,KAAQ,aAAe,EAEvB,KAAQ,UAAY,GAEpB,KAAA,UAAuB,IAAM,CAAC,EAC9B,KAAA,aAA6B,IAAM,CAAC,EAOpC,KAAQ,aAAe,EAJrB,KAAK,WAAaA,CACpB,CAKA,QAAQd,EAAyB,CAC/B,GAAI,KAAK,WAAaA,EAAK,aAAe,EAAG,OAY7C,GAVK,KAAK,cACR,KAAK,YAAc,IAAI,aAAa,CAAE,WAAY,KAAK,WAAY,EACnE,KAAK,aAAe,KAAK,YAAY,aAGnC,KAAK,YAAY,QAAU,aAC7B,KAAK,YAAY,OAAA,EAGnB,KAAK,eACD,KAAK,cAAgB,GAAK,KAAK,aAAe,MAAQ,EAAG,CAC3D,MAAMe,EAAe,IAAI,WAAWf,CAAI,EACxC,IAAIgB,EAAS,EACb,QAASX,EAAI,EAAGA,EAAI,KAAK,IAAIU,EAAa,OAAQ,GAAG,EAAGV,IAAK,CAC3D,MAAMY,EAAM,KAAK,IAAIF,EAAaV,CAAC,CAAC,EAChCY,EAAMD,IAAQA,EAASC,EAC7B,CACA,QAAQ,IAAI,0BAA0B,KAAK,YAAY,UAAUjB,EAAK,UAAU,aAAa,KAAK,YAAY,KAAK,eAAe,KAAK,UAAU,cAAcgB,CAAM,cAAc,KAAK,aAAa,QAAQ,CAAC,CAAC,YAAY,KAAK,YAAY,YAAY,QAAQ,CAAC,CAAC,EAAE,CACtQ,CAEA,MAAMb,EAAQ,IAAI,WAAWH,CAAI,EAC3BI,EAAUF,EAAeC,CAAK,EAG9Be,EAAQV,EAAkBJ,CAAO,EACvC,KAAK,aAAac,CAAK,EAGvB,MAAMC,EAAS,KAAK,YAAY,aAAa,EAAGf,EAAQ,OAAQ,KAAK,UAAU,EAC/Ee,EAAO,eAAe,CAAC,EAAE,IAAIf,CAAO,EAEpC,MAAMgB,EAAS,KAAK,YAAY,mBAAA,EAChCA,EAAO,OAASD,EAChBC,EAAO,QAAQ,KAAK,YAAY,WAAW,EAE3C,MAAMC,EAAM,KAAK,YAAY,YACzB,KAAK,aAAeA,EACtB,KAAK,aAAeA,EAAMV,EACjB,KAAK,aAAeU,EAAMT,IACnC,KAAK,aAAeS,EAAMV,GAE5BS,EAAO,MAAM,KAAK,YAAY,EAC9B,KAAK,cAAgBD,EAAO,QAC9B,CAGA,MAAM,UAA0B,CAC1B,KAAK,WAAa,KAAK,YAE3B,KAAK,UAAY,MAAM,UAAU,aAAa,aAAa,CACzD,MAAO,CACL,WAAY,KAAK,WACjB,aAAc,EACd,iBAAkB,GAClB,iBAAkB,GAClB,gBAAiB,EAAA,CACnB,CACD,EAED,KAAK,OAAS,IAAI,aAAa,CAAE,WAAY,KAAK,WAAY,EAC9D,KAAK,UAAY,KAAK,OAAO,wBAAwB,KAAK,SAAS,EAGnE,KAAK,aAAe,KAAK,OAAO,sBAAsB,KAAM,EAAG,CAAC,EAChE,KAAK,aAAa,eAAkBhC,GAAM,CACxC,GAAI,KAAK,UAAW,OACpB,MAAMiB,EAAUjB,EAAE,YAAY,eAAe,CAAC,EACxCgB,EAAQG,EAAeF,CAAO,EACpC,KAAK,UAAUD,EAAM,MAAqB,CAC5C,EAEA,KAAK,UAAU,QAAQ,KAAK,YAAY,EACxC,KAAK,aAAa,QAAQ,KAAK,OAAO,WAAW,EACnD,CAEA,SAAgB,CASd,GARI,KAAK,eACP,KAAK,aAAa,WAAA,EAClB,KAAK,aAAe,MAElB,KAAK,YACP,KAAK,UAAU,WAAA,EACf,KAAK,UAAY,MAEf,KAAK,UAAW,CAClB,UAAWmB,KAAS,KAAK,UAAU,UAAA,EACjCA,EAAM,KAAA,EAER,KAAK,UAAY,IACnB,CACI,KAAK,SACP,KAAK,OAAO,MAAA,EAAQ,MAAM,IAAM,CAAC,CAAC,EAClC,KAAK,OAAS,KAElB,CAGA,QAAe,CACR,KAAK,cACR,KAAK,YAAc,IAAI,aAAa,CAAE,WAAY,KAAK,WAAY,EACnE,KAAK,aAAe,KAAK,YAAY,aAEnC,KAAK,YAAY,QAAU,aAC7B,KAAK,YAAY,OAAA,CAErB,CAEA,SAAgB,CACd,KAAK,UAAY,GACjB,KAAK,QAAA,EACD,KAAK,cACP,KAAK,YAAY,MAAA,EAAQ,MAAM,IAAM,CAAC,CAAC,EACvC,KAAK,YAAc,KAEvB,CACF,CChJA,MAAMC,EAAc,IACdC,EAAa,cACbC,EAAqB,EAEpB,MAAMC,CAAY,CAAlB,aAAA,CACL,KAAQ,OAAmC,KAC3C,KAAQ,IAAuC,KAC/C,KAAQ,WAAsC,KAC9C,KAAQ,YAAkC,KAC1C,KAAQ,cAA0C,KAClD,KAAQ,WAA8C,KACtD,KAAQ,WAAuC,KAC/C,KAAQ,QAA2C,KACnD,KAAQ,gBAAyD,KACjE,KAAQ,YAAmC,KAC3C,KAAQ,eAAiB,EACzB,KAAQ,mBAAqB,IAE7B,KAAA,cAAqF,KACrF,KAAA,qBAA0J,KAC1J,KAAQ,YAAmC,KAC3C,KAAQ,wBAA0B,IAClC,KAAQ,eAAiB,EACzB,KAAQ,iBAAmB,GAoB3B,KAAQ,gBAAkB,GAC1B,KAAQ,eAAiB,CAAA,CAnBzB,gBAAgBC,EAAiC,CAC/C,KAAK,OAASA,EACd,KAAK,IAAMA,EAAO,WAAW,IAAI,CACnC,CAEA,YAAYC,EAA6B,CACvC,GAAI,CAAC,KAAK,QAAU,CAAC,KAAK,IAAK,OAC/B,KAAM,CAAE,MAAAC,EAAO,OAAAC,EAAQ,KAAA9B,EAAM,YAAA+B,EAAa,OAAAC,EAAQ,WAAAC,EAAY,UAAAC,GAAcN,EAC5E,GAAI,EAAAC,GAAS,GAAKC,GAAU,GAE5B,IAAIE,IAAWT,EAAa,CAC1B,KAAK,gBAAgBvB,EAAM6B,EAAOC,EAAQC,EAAaE,EAAYC,CAAS,EAC5E,MACF,CAEA,KAAK,gBAAgBlC,EAAM6B,EAAOC,EAAQC,CAAW,EACvD,CAKQ,gBACN/B,EAAmBmC,EAAgBC,EACnCL,EAAqBE,EAAqBC,EACpC,CACN,GAAIlC,EAAK,aAAe,EAAG,OAE3B,GAAI,CAAC,KAAK,gBAAiB,CACzB,GAAI,CAACiC,EAAY,OACjB,KAAK,gBAAkB,EACzB,CAEA,GAAI,CAAC,KAAK,aAAe,KAAK,YAAY,QAAU,SAAU,CAK5D,GAJI,KAAK,gBAAkBR,IAC3B,KAAK,YAAc,KAAK,kBAAA,EACpB,CAAC,KAAK,eACV,KAAK,gBAAkB,GACnB,CAACQ,GAAY,OACjB,KAAK,gBAAkB,EACzB,CAEA,KAAK,iBACL,MAAMI,EAAO,KAAK,eAAiB,MACnC,KAAK,eAAe,IAAIA,EAAMN,CAAW,EAEzC,GAAI,CACF,KAAK,YAAY,OAAO,IAAI,kBAAkB,CAC5C,KAAME,EAAa,MAAQ,QAC3B,UAAWI,EACX,KAAArC,CAAA,CACD,CAAC,CACJ,MAAY,CACV,KAAK,iBACL,KAAK,gBAAkB,EACzB,CACF,CAEQ,mBAAyC,CAC/C,GAAI,OAAO,WAAW,cAAiB,WAAY,OAAO,KAE1D,GAAI,CACF,MAAMsC,EAAU,IAAI,aAAa,CAC/B,OAASC,GAAO,CACd,GAAI,CACF,GAAI,CAAC,KAAK,QAAU,CAAC,KAAK,IAAK,CAAEA,EAAG,MAAA,EAAS,MAAQ,CACrD,MAAMR,EAAc,KAAK,eAAe,IAAIQ,EAAG,SAAS,GAAK,EAC7D,KAAK,eAAe,OAAOA,EAAG,SAAS,EAEvC,MAAMC,EAAID,EAAG,WACPE,EAAIF,EAAG,YACPG,EAAYX,IAAgB,GAAKA,IAAgB,EACjDY,EAAWD,EAAYD,EAAID,EAC3BI,EAAWF,EAAYF,EAAIC,GAE7B,KAAK,OAAO,QAAUE,GAAY,KAAK,OAAO,SAAWC,KAC3D,KAAK,OAAO,MAAQD,EACpB,KAAK,OAAO,OAASC,GAGvB,KAAK,IAAK,KAAA,EACNb,IAAgB,GAClB,KAAK,IAAK,UAAUY,EAAU,CAAC,EAC/B,KAAK,IAAK,OAAO,KAAK,GAAK,CAAC,GACnBZ,IAAgB,GACzB,KAAK,IAAK,UAAUY,EAAUC,CAAQ,EACtC,KAAK,IAAK,OAAO,KAAK,EAAE,GACfb,IAAgB,IACzB,KAAK,IAAK,UAAU,EAAGa,CAAQ,EAC/B,KAAK,IAAK,OAAO,CAAC,KAAK,GAAK,CAAC,GAE/B,KAAK,IAAK,UAAUL,EAAI,EAAG,CAAC,EAC5B,KAAK,IAAK,QAAA,CACZ,QAAA,CACEA,EAAG,MAAA,CACL,CACF,EACA,MAAO,IAAM,CACX,KAAK,iBACL,KAAK,eAAe,MAAA,CACtB,CAAA,CACD,EAED,OAAAD,EAAQ,UAAU,CAAE,MAAOd,EAAY,mBAAoB,GAAM,EACjE,KAAK,eAAiB,EACfc,CACT,MAAQ,CACN,OAAO,IACT,CACF,CAEQ,gBAAgBtC,EAAmB6B,EAAeC,EAAgBC,EAA2B,CACnG,GAAI,CAAC,KAAK,QAAU,CAAC,KAAK,IAAK,OAE/B,MAAMW,EAAYX,IAAgB,GAAKA,IAAgB,EACjDY,EAAWD,EAAYZ,EAASD,EAChCe,EAAWF,EAAYb,EAAQC,EAOrC,IALI,KAAK,OAAO,QAAUa,GAAY,KAAK,OAAO,SAAWC,KAC3D,KAAK,OAAO,MAAQD,EACpB,KAAK,OAAO,OAASC,GAGnB,OAAQ,WAAmB,YAAe,WAC5C,GAAI,CACF,MAAML,EAAK,IAAK,WAAmB,WAAW,IAAI,WAAWvC,CAAI,EAAG,CAClE,OAAQ,OACR,WAAY6B,EACZ,YAAaC,EACb,UAAW,CAAA,CACZ,EACD,KAAK,IAAI,KAAA,EACLC,IAAgB,GAClB,KAAK,IAAI,UAAUY,EAAU,CAAC,EAC9B,KAAK,IAAI,OAAO,KAAK,GAAK,CAAC,GAClBZ,IAAgB,GACzB,KAAK,IAAI,UAAUY,EAAUC,CAAQ,EACrC,KAAK,IAAI,OAAO,KAAK,EAAE,GACdb,IAAgB,IACzB,KAAK,IAAI,UAAU,EAAGa,CAAQ,EAC9B,KAAK,IAAI,OAAO,CAAC,KAAK,GAAK,CAAC,GAE9B,KAAK,IAAI,UAAUL,EAAI,EAAG,CAAC,EAC3B,KAAK,IAAI,QAAA,EACTA,EAAG,MAAA,EACH,MACF,MAAQ,CAER,CAGF,MAAMM,EAAO,IAAI,WAAW7C,CAAI,EAC1B8C,EAAO,KAAK,WAAWD,EAAMhB,EAAOC,CAAM,EAC1CiB,EAAU,IAAI,UAAU,IAAI,kBAAkBD,EAAK,MAAqB,EAAGjB,EAAOC,CAAM,EAE1FC,GAAe,GAAKA,GAAe,GAChC,KAAK,aACR,KAAK,WAAa,SAAS,cAAc,QAAQ,EACjD,KAAK,QAAU,KAAK,WAAW,WAAW,IAAI,GAEhD,KAAK,WAAW,MAAQF,EACxB,KAAK,WAAW,OAASC,EACzB,KAAK,QAAS,aAAaiB,EAAS,EAAG,CAAC,EAExC,KAAK,IAAI,KAAA,EACLhB,IAAgB,GAClB,KAAK,IAAI,UAAUY,EAAU,CAAC,EAC9B,KAAK,IAAI,OAAO,KAAK,GAAK,CAAC,GAClBZ,IAAgB,GACzB,KAAK,IAAI,UAAUY,EAAUC,CAAQ,EACrC,KAAK,IAAI,OAAO,KAAK,EAAE,GACdb,IAAgB,IACzB,KAAK,IAAI,UAAU,EAAGa,CAAQ,EAC9B,KAAK,IAAI,OAAO,CAAC,KAAK,GAAK,CAAC,GAE9B,KAAK,IAAI,UAAU,KAAK,WAAY,EAAG,CAAC,EACxC,KAAK,IAAI,QAAA,GAET,KAAK,IAAI,aAAaG,EAAS,EAAG,CAAC,CAEvC,CAEA,MAAM,YAAYC,EAA2BnB,EAAQ,IAAKC,EAAS,IAAKmB,EAAM,GAAmB,CAC/F,KAAK,WAAaD,EAElB,MAAME,EAAS,MAAM,UAAU,aAAa,aAAa,CACvD,MAAO,CAAE,MAAO,CAAE,MAAOrB,GAAS,OAAQ,CAAE,MAAOC,GAAU,UAAW,CAAE,MAAOmB,EAAI,EACrF,MAAO,EAAA,CACR,EACD,KAAK,YAAcC,EACnBF,EAAQ,UAAYE,EACpBF,EAAQ,MAAQ,GAChB,MAAMA,EAAQ,KAAA,EAEE,KAAK,kBAAA,EAEnB,KAAK,iBAAiBE,EAAQrB,EAAOC,EAAQmB,CAAG,GAEhD,KAAK,cAAgB,SAAS,cAAc,QAAQ,EACpD,KAAK,cAAc,MAAQpB,EAC3B,KAAK,cAAc,OAASC,EAC5B,KAAK,WAAa,KAAK,cAAc,WAAW,KAAM,CAAE,mBAAoB,GAAM,EAClF,KAAK,gBAAkB,YAAY,IAAM,KAAK,kBAAmB,KAAK,MAAM,IAAOmB,CAAG,CAAC,EAE3F,CAEA,YAAmB,CAKjB,GAJI,KAAK,kBACP,cAAc,KAAK,eAAe,EAClC,KAAK,gBAAkB,MAErB,KAAK,aAAe,KAAK,YAAY,QAAU,SACjD,GAAI,CAAE,KAAK,YAAY,MAAA,CAAS,MAAQ,CAAC,CAE3C,KAAK,YAAc,KACf,KAAK,cACP,KAAK,YAAY,YAAY,QAAQ,GAAK,EAAE,MAAM,EAClD,KAAK,YAAc,MAEjB,KAAK,aACP,KAAK,WAAW,UAAY,KAC5B,KAAK,WAAa,MAEpB,KAAK,cAAgB,KACrB,KAAK,WAAa,IACpB,CAEQ,mBAA6B,CACnC,OAAO,OAAO,WAAW,cAAiB,YACrC,OAAQ,WAAmB,2BAA8B,UAChE,CAEQ,iBAAiBC,EAAqBrB,EAAeC,EAAgBmB,EAAmB,CAC9F,MAAM3B,EAAQ4B,EAAO,eAAA,EAAiB,CAAC,EACvC,GAAI,CAAC5B,EAAO,OAEZ,IAAI6B,EAAUtB,EACVuB,EAAUtB,EACVuB,EAAa,EACjB,MAAMC,MAAkB,IAExB,KAAK,YAAc,IAAI,aAAa,CAClC,OAAQ,CAACC,EAAOC,IAAS,SACvB,GAAI,CAAC,KAAK,qBAAsB,OAChC,MAAMC,EAAM,IAAI,YAAYF,EAAM,UAAU,EAC5CA,EAAM,OAAOE,CAAG,EAChB,MAAMC,EAAQH,EAAM,OAAS,MACvBI,IAAS3E,EAAAwE,GAAA,YAAAA,EAAM,gBAAN,YAAAxE,EAAqB,aAAcmE,EAC5CS,IAASC,EAAAL,GAAA,YAAAA,EAAM,gBAAN,YAAAK,EAAqB,cAAeT,EACnD,IAAIU,EAAY,EAChB,MAAMC,EAAYT,EAAY,IAAIC,EAAM,SAAS,EAC7CQ,GAAa,OACfT,EAAY,OAAOC,EAAM,SAAS,EAClCO,EAAY,KAAK,MAAQC,GAE3B,MAAMC,EAAQT,EAAM,UAAY,IAChC,KAAK,qBAAqBE,EAAKE,EAAQC,EAAQI,EAAON,EAAOI,CAAS,CACxE,EACA,MAAQ3E,GAAM,CAAE,QAAQ,MAAM,+BAAgCA,CAAC,CAAG,CAAA,CACnE,EAED,KAAK,YAAY,UAAU,CACzB,MAAO,cACP,MAAOgE,EACP,OAAQC,EACR,QAAS,IACT,UAAWH,EACX,YAAa,WACb,YAAa,WACb,IAAK,CAAE,OAAQ,QAAA,CAAS,CAClB,EAGR,MAAMgB,EADY,IAAK,WAAmB,0BAA0B,CAAE,MAAA3C,EAAO,EACpD,SAAS,UAAA,GAEjB,SAAY,CAC3B,KAAO,KAAK,aAAe,KAAK,YAAY,QAAU,UACpD,GAAI,CACF,KAAM,CAAE,MAAOM,EAAO,KAAAsC,GAAS,MAAMD,EAAO,KAAA,EAC5C,GAAIC,GAAQ,CAACtC,EAAO,MACpB,GAAI,KAAK,YAAY,QAAU,aAAc,CAAEA,EAAM,MAAA,EAAS,QAAU,CAExE,MAAMP,EAAM,KAAK,IAAA,EACX8C,EAAe9C,EAAM,KAAK,eAC1B+C,EAAU,KAAK,kBAAoBD,GAAgB,KAAK,yBAA2Bd,IAAe,EAExGC,EAAY,IAAI1B,EAAM,UAAWP,CAAG,EACpC,KAAK,YAAY,OAAOO,EAAO,CAAE,SAAUwC,EAAS,EACpDxC,EAAM,MAAA,EAENyB,IACIe,IACF,KAAK,eAAiB/C,EACtB,KAAK,iBAAmB,GAE5B,MAAQ,CAAE,KAAO,CAErB,GACA,CACF,CAEQ,iBAAwB,CAE9B,GADI,CAAC,KAAK,YAAc,CAAC,KAAK,eAAiB,CAAC,KAAK,YAAc,CAAC,KAAK,eACrE,KAAK,WAAW,WAAa,EAAG,OAEpC,MAAMmB,EAAI,KAAK,cAAc,MACvBC,EAAI,KAAK,cAAc,OAC7B,KAAK,WAAW,UAAU,KAAK,WAAY,EAAG,EAAGD,EAAGC,CAAC,EACrD,MAAMM,EAAU,KAAK,WAAW,aAAa,EAAG,EAAGP,EAAGC,CAAC,EACvD,KAAK,cAAcM,EAAQ,KAAK,OAAQP,EAAGC,CAAC,CAC9C,CAEQ,WAAWI,EAAkBhB,EAAeC,EAAmC,CACrF,MAAMgB,EAAO,IAAI,kBAAkBjB,EAAQC,EAAS,CAAC,EAC/CuC,EAAaxC,EAAQC,EAE3B,QAASwC,EAAI,EAAGA,EAAIxC,EAAQwC,IAC1B,QAASjE,EAAI,EAAGA,EAAIwB,EAAOxB,IAAK,CAC9B,MAAMkE,EAAOD,EAAIzC,EAAQxB,EACnBmE,EAAQH,GAAcC,GAAK,GAAKzC,GAASxB,EAAI,IAE7CoE,EAAI5B,EAAK0B,CAAI,EACb,EAAI1B,EAAK2B,CAAK,EAAI,IAClBE,EAAI7B,EAAK2B,EAAQ,CAAC,EAAI,IAEtBG,EAAUJ,EAAO,EACvBzB,EAAK6B,CAAO,EAAQC,EAAMH,EAAI,MAAQC,CAAC,EACvC5B,EAAK6B,EAAU,CAAC,EAAIC,EAAMH,EAAI,KAAQ,EAAI,KAAQC,CAAC,EACnD5B,EAAK6B,EAAU,CAAC,EAAIC,EAAMH,EAAI,MAAQ,CAAC,EACvC3B,EAAK6B,EAAU,CAAC,EAAI,GACtB,CAEF,OAAO7B,CACT,CAEA,aAAoB,CACd,KAAK,QAAU,KAAK,KACtB,KAAK,IAAI,UAAU,EAAG,EAAG,KAAK,OAAO,MAAO,KAAK,OAAO,MAAM,CAElE,CAEA,SAAgB,CAEd,GADA,KAAK,WAAA,EACD,KAAK,aAAe,KAAK,YAAY,QAAU,SACjD,GAAI,CAAE,KAAK,YAAY,MAAA,CAAS,MAAQ,CAAC,CAE3C,KAAK,YAAc,KACnB,KAAK,eAAe,MAAA,EACpB,KAAK,OAAS,KACd,KAAK,IAAM,IACb,CACF,CAEA,SAAS8B,EAAMF,EAAmB,CAChC,OAAOA,EAAI,EAAI,EAAIA,EAAI,IAAM,IAAMA,EAAI,CACzC,CC3XO,MAAMG,CAAiB,CAAvB,aAAA,CACL,KAAQ,UAAY,GAAsB,CAE1C,QAAQC,EAAsB,CAC5B,KAAK,MAAM,IAAIA,EAAK,OAAQ,CAAE,GAAGA,EAAM,CACzC,CAEA,YAAYC,EAAgBC,EAAwB,CAClD,MAAMF,EAAO,KAAK,MAAM,IAAIC,CAAM,EAC7BD,IACLA,EAAK,MAAQE,EACTA,IAAU,SACZ,KAAK,MAAM,OAAOD,CAAM,EAE5B,CAEA,cAAcA,EAAgBE,EAAwB,CACpD,MAAMH,EAAO,KAAK,MAAM,IAAIC,CAAM,EAC9BD,IACFA,EAAK,QAAUG,EAEnB,CAEA,WAAWF,EAAsB,CAC/B,KAAK,MAAM,OAAOA,CAAM,CAC1B,CAEA,QAAQA,EAAsC,CAC5C,OAAO,KAAK,MAAM,IAAIA,CAAM,CAC9B,CAEA,eAAsC,CACpC,UAAWD,KAAQ,KAAK,MAAM,OAAA,EAC5B,GAAIA,EAAK,QAAU,YAAcA,EAAK,QAAU,SAC9C,OAAOA,CAIb,CAEA,iBAA8B,CAC5B,MAAMI,EAAqB,CAAA,EAC3B,UAAWJ,KAAQ,KAAK,MAAM,OAAA,GACxBA,EAAK,QAAU,WAAaA,EAAK,QAAU,gBAC7CI,EAAO,KAAKJ,CAAI,EAGpB,OAAOI,CACT,CAEA,aAA0B,CACxB,OAAO,MAAM,KAAK,KAAK,MAAM,QAAQ,CACvC,CAEA,gBAA0B,CACxB,UAAWJ,KAAQ,KAAK,MAAM,OAAA,EAC5B,GAAIA,EAAK,QAAU,QAAS,MAAO,GAErC,MAAO,EACT,CAEA,OAAc,CACZ,KAAK,MAAM,MAAA,CACb,CACF,CChEO,SAASK,EAASC,EAA8B,CACrD,MAAMC,EAAQD,EAAM,OAAS,QAEvBE,EAAUF,EAAM,cAAgB,UAChCG,EAASH,EAAM,aAAe,UAC9BI,EAAKJ,EAAM,kBAAoBC,EAAQ,UAAY,WACnDI,EAAUL,EAAM,eAAiBC,EAAQ,UAAY,WACrDK,EAAON,EAAM,YAAcC,EAAQ,UAAY,WAC/CM,EAAUP,EAAM,qBAAuBC,EAAQ,UAAY,WAC3DO,EAASR,EAAM,cAAgB,OAC/BS,EAAOT,EAAM,YAAc,oEAG3BU,EAAUT,EAAQ,mBAAqB,yBACvCU,EAAeV,EAAQ,kBAAoB,wBAC3CW,EAAgBX,EAAQ,mBAAqB,yBAC7CY,EAASZ,EAAQ,mBAAqB,kBACtCa,EAAWb,EAAQ,mBAAqB,kBACxCc,EAASd,EAAQ,mBAAqB,yBACtCe,EAAcf,EAAQ,mBAAqB,wBAEjD,MAAO;AAAA;AAAA;AAAA,qBAGYQ,CAAI;AAAA,eACVH,CAAI;AAAA,mBACAJ,CAAO;AAAA,kBACRC,CAAM;AAAA,cACVC,CAAE;AAAA,mBACGC,CAAO;AAAA,gBACVC,CAAI;AAAA,oBACAC,CAAO;AAAA,kBACTC,CAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAQHC,CAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAiBMI,CAAM;AAAA;AAAA;AAAA;AAAA;AAAA,qEAKgCC,CAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0CAsCnCD,CAAM;AAAA,qCACXA,CAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAYZC,CAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAqBNC,CAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mDA2BYL,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yCAwGjBA,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAgCVC,CAAY;AAAA,+DACaC,CAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAuLlDI,CAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oCASDN,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAsFjBM,CAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAUXA,CAAW;AAAA;AAAA,6CAEQN,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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"}