@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.
package/dist/z-api-call.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"z-api-call.mjs","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\">📞</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\">📞</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","_b","buf","isKey","codedW","codedH","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","_d","_e","_f","_g","_h","_i","_j","_k","_l","_m","_n","_o","_p","_q","_r","_s","_t","outCall","vCall","firstByte","frameData","ySize","idx","uvOff","VideoFormat","VideoOrientation","init","ZAPICall"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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;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"}
|
|
1
|
+
{"version":3,"file":"z-api-call.mjs","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\">📞</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\">📞</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","_b","buf","isKey","codedW","codedH","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","_d","_e","_f","_g","_h","_i","_j","_k","_l","_m","_n","_o","_p","_q","_r","_s","_t","outCall","vCall","firstByte","frameData","ySize","idx","uvOff","VideoFormat","VideoOrientation","init","ZAPICall"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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;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"}
|