@z-api/call 1.0.0-staging.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/README.md ADDED
@@ -0,0 +1,590 @@
1
+ # @z-api/call
2
+
3
+ SDK para integrar chamadas VoIP do WhatsApp em aplicações web. Fornece um widget pronto (webphone) com discador, lista de chamadas e tela de ligação ativa, além de uma API programática completa.
4
+
5
+ ## Instalação
6
+
7
+ ```bash
8
+ npm install @z-api/call
9
+ ```
10
+
11
+ ### Via CDN (script tag)
12
+
13
+ ```html
14
+ <script src="https://unpkg.com/@z-api/call/dist/z-api-call.global.js"></script>
15
+ <script>
16
+ const client = ZAPICall.init({
17
+ instanceId: 'SUA_INSTANCE_ID',
18
+ getToken: async () => {
19
+ const res = await fetch('https://seu-backend.com/call-token');
20
+ const data = await res.json();
21
+ return data.token;
22
+ },
23
+ });
24
+ </script>
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ```typescript
30
+ import { init } from '@z-api/call';
31
+
32
+ const client = init({
33
+ instanceId: 'SUA_INSTANCE_ID',
34
+ getToken: async () => {
35
+ // Chama SEU backend, que por sua vez chama a Z-API para obter o token efêmero
36
+ const res = await fetch('https://seu-backend.com/call-token');
37
+ const data = await res.json();
38
+ return data.token;
39
+ },
40
+ });
41
+
42
+ // Ouvir eventos
43
+ client.on('call:incoming', (call) => {
44
+ console.log('Chamada recebida de', call.from);
45
+ });
46
+
47
+ client.on('connected', () => {
48
+ console.log('Conectado ao servidor');
49
+ });
50
+ ```
51
+
52
+ ## Autenticação (getToken)
53
+
54
+ A SDK utiliza tokens efêmeros para autenticação. Em vez de passar um token fixo, você fornece uma função `getToken` que é chamada sempre que a SDK precisa se conectar (inclusive em reconexões).
55
+
56
+ ### Fluxo de autenticação
57
+
58
+ ```
59
+ ┌──────────┐ getToken() ┌───────────────┐ POST /call-token ┌─────────────┐
60
+ │ SDK │ ──────────────────► │ Seu Backend │ ──────────────────────► │ Z-API │
61
+ │ (browser)│ │ │ │ │
62
+ │ │ ◄────────────────── │ │ ◄────────────────────── │ │
63
+ │ │ token efêmero │ │ token efêmero │ │
64
+ └──────────┘ └───────────────┘ └─────────────┘
65
+ ```
66
+
67
+ 1. A SDK chama a função `getToken` fornecida por você
68
+ 2. Sua função faz uma requisição ao **seu backend**
69
+ 3. Seu backend chama a API da Z-API para gerar o token efêmero:
70
+
71
+ ```
72
+ POST https://api.z-api.io/instances/{ID_INSTANCE}/token/{TOKEN_INSTANCE}/call-token
73
+ Header: client-token: SEU_CLIENT_TOKEN
74
+ ```
75
+
76
+ 4. A Z-API retorna o token efêmero
77
+ 5. Seu backend repassa o token para o frontend
78
+ 6. A SDK usa o token para conectar via WebSocket
79
+
80
+ ### Exemplo de backend (Node.js)
81
+
82
+ ```javascript
83
+ app.get('/call-token', async (req, res) => {
84
+ const response = await fetch(
85
+ `https://api.z-api.io/instances/${ID_INSTANCE}/token/${TOKEN_INSTANCE}/call-token`,
86
+ {
87
+ method: 'POST',
88
+ headers: { 'client-token': SEU_CLIENT_TOKEN },
89
+ }
90
+ );
91
+ const data = await response.json();
92
+ res.json({ token: data.token });
93
+ });
94
+ ```
95
+
96
+ ### Exemplo de getToken no frontend
97
+
98
+ ```typescript
99
+ const client = init({
100
+ instanceId: 'SUA_INSTANCE_ID',
101
+ getToken: async () => {
102
+ const res = await fetch('https://seu-backend.com/call-token');
103
+ const { token } = await res.json();
104
+ return token;
105
+ },
106
+ });
107
+ ```
108
+
109
+ > **Importante:** Nunca exponha o `TOKEN_INSTANCE` ou `client-token` no frontend. A chamada à Z-API deve ser feita pelo seu backend.
110
+
111
+ ## Opções de Inicialização
112
+
113
+ ```typescript
114
+ const client = init({
115
+ // --- Obrigatórios ---
116
+ instanceId: string, // ID da instância Z-API
117
+ getToken: () => Promise<string>, // Função que retorna o token efêmero
118
+
119
+ // --- Opcionais ---
120
+ autoWidget: true, // Criar widget automaticamente (default: true)
121
+ showVideoDialButton: false, // Exibir botão de vídeo chamada no discador (default: false)
122
+ position: 'bottom-right', // Posição do widget (ver abaixo)
123
+ theme: { ... }, // Personalização visual (ver Temas)
124
+
125
+ // --- Callbacks ---
126
+ onIncomingCall: (call) => {}, // Chamada recebida
127
+ onCallTerminated: (callId) => {}, // Chamada encerrada
128
+ onConnectionChange: (connected) => {}, // Conexão mudou
129
+ onMakeCall: (number) => {}, // Chamada de saída iniciada
130
+ });
131
+ ```
132
+
133
+ ### Posições do Widget
134
+
135
+ | Valor | Posição |
136
+ |-------|---------|
137
+ | `'bottom-right'` | Canto inferior direito (default) |
138
+ | `'bottom-left'` | Canto inferior esquerdo |
139
+ | `'top-right'` | Canto superior direito |
140
+ | `'top-left'` | Canto superior esquerdo |
141
+
142
+ ## Temas
143
+
144
+ ### Dark / Light Mode
145
+
146
+ ```typescript
147
+ // Tema escuro (default)
148
+ const client = init({
149
+ instanceId: '...',
150
+ getToken: async () => { /* ... */ },
151
+ theme: { mode: 'dark' },
152
+ });
153
+
154
+ // Tema claro
155
+ const client = init({
156
+ instanceId: '...',
157
+ getToken: async () => { /* ... */ },
158
+ theme: { mode: 'light' },
159
+ });
160
+ ```
161
+
162
+ ### Personalização Completa
163
+
164
+ Todas as propriedades são opcionais. Os valores default dependem do `mode`.
165
+
166
+ ```typescript
167
+ theme: {
168
+ mode: 'dark', // 'dark' | 'light'
169
+ primaryColor: '#00a884', // Cor principal (botões, destaques)
170
+ dangerColor: '#f44336', // Cor de perigo (rejeitar, encerrar)
171
+ backgroundColor: '#202c33',// Fundo dos cards e numpad
172
+ surfaceColor: '#111b21', // Fundo do painel
173
+ textColor: '#e9edef', // Cor do texto principal
174
+ textSecondaryColor: '#8696a0', // Cor do texto secundário
175
+ borderRadius: '16px', // Raio de borda do painel
176
+ fontFamily: 'Inter, sans-serif', // Família de fontes
177
+ }
178
+ ```
179
+
180
+ **Defaults por modo:**
181
+
182
+ | Propriedade | Dark | Light |
183
+ |-------------|------|-------|
184
+ | `backgroundColor` | `#202c33` | `#f0f2f5` |
185
+ | `surfaceColor` | `#111b21` | `#ffffff` |
186
+ | `textColor` | `#e9edef` | `#111b21` |
187
+ | `textSecondaryColor` | `#8696a0` | `#667781` |
188
+
189
+ ## API do Cliente
190
+
191
+ ### Métodos
192
+
193
+ #### `accept(callId: string): void`
194
+
195
+ Aceita uma chamada recebida.
196
+
197
+ ```typescript
198
+ client.on('call:incoming', (call) => {
199
+ client.accept(call.callId);
200
+ });
201
+ ```
202
+
203
+ #### `reject(callId: string): void`
204
+
205
+ Rejeita ou encerra uma chamada.
206
+
207
+ ```typescript
208
+ client.reject(callId);
209
+ ```
210
+
211
+ #### `makeCall(number: string, isVideo?: boolean): void`
212
+
213
+ Inicia uma chamada de saída (áudio ou vídeo).
214
+
215
+ ```typescript
216
+ client.makeCall('5511999999999'); // chamada de áudio
217
+ client.makeCall('5511999999999', true); // chamada de vídeo
218
+ ```
219
+
220
+ > **Nota:** Requer suporte no backend. A SDK envia o evento `call:make` via WebSocket.
221
+
222
+ #### `setCamera(enabled: boolean): Promise<void>`
223
+
224
+ Liga ou desliga a câmera durante uma chamada. Se a chamada for de áudio, automaticamente solicita upgrade para vídeo.
225
+
226
+ ```typescript
227
+ await client.setCamera(true); // ligar câmera
228
+ await client.setCamera(false); // desligar câmera
229
+ ```
230
+
231
+ #### `isCameraActive(): boolean`
232
+
233
+ Retorna se a câmera está ativa.
234
+
235
+ ```typescript
236
+ if (client.isCameraActive()) {
237
+ console.log('Câmera ligada');
238
+ }
239
+ ```
240
+
241
+ #### `mute(muted: boolean): void`
242
+
243
+ Ativa/desativa o microfone.
244
+
245
+ ```typescript
246
+ client.mute(true); // mutar
247
+ client.mute(false); // desmutar
248
+ ```
249
+
250
+ #### `getCalls(): CallInfo[]`
251
+
252
+ Retorna todas as chamadas ativas.
253
+
254
+ ```typescript
255
+ const calls = client.getCalls();
256
+ calls.forEach(c => console.log(c.callId, c.state));
257
+ ```
258
+
259
+ #### `getActiveCall(): CallInfo | undefined`
260
+
261
+ Retorna a chamada ativa (accepted/active) se houver.
262
+
263
+ ```typescript
264
+ const call = client.getActiveCall();
265
+ if (call) {
266
+ console.log('Em ligação com', call.from);
267
+ }
268
+ ```
269
+
270
+ #### `isConnected(): boolean`
271
+
272
+ Verifica se está conectado ao servidor.
273
+
274
+ ```typescript
275
+ if (client.isConnected()) {
276
+ console.log('Online');
277
+ }
278
+ ```
279
+
280
+ #### `destroy(): void`
281
+
282
+ Destrói o cliente, fecha conexões e remove o widget do DOM.
283
+
284
+ ```typescript
285
+ client.destroy();
286
+ ```
287
+
288
+ ### Eventos
289
+
290
+ ```typescript
291
+ // Conexão estabelecida
292
+ client.on('connected', () => { });
293
+
294
+ // Conexão perdida
295
+ client.on('disconnected', () => { });
296
+
297
+ // Chamada recebida
298
+ client.on('call:incoming', (call: CallInfo) => {
299
+ console.log(call.callId, call.from, call.isVideo);
300
+ });
301
+
302
+ // Estado da chamada mudou
303
+ client.on('call:state', (callId: string, state: CallState) => {
304
+ // state: 'ringing' | 'preaccepted' | 'accepted' | 'active' | 'ended'
305
+ });
306
+
307
+ // Chamada encerrada
308
+ client.on('call:terminated', (callId: string, reason?: string) => { });
309
+
310
+ // Vídeo ativado/desativado durante a chamada (upgrade/downgrade)
311
+ client.on('call:video-state', (callId: string, isVideo: boolean) => {
312
+ console.log(isVideo ? 'Chamada mudou para vídeo' : 'Chamada voltou para áudio');
313
+ });
314
+
315
+ // Chamada de saída iniciada
316
+ client.on('call:outgoing', (call: CallInfo) => { });
317
+
318
+ // Chamada de saída iniciada (número)
319
+ client.on('call:make', (number: string) => { });
320
+
321
+ // Nível de áudio (0 a 1)
322
+ client.on('audio:level', (level: number) => {
323
+ console.log('Volume:', Math.round(level * 100) + '%');
324
+ });
325
+
326
+ // Erro
327
+ client.on('error', (error: Error) => {
328
+ console.error(error.message);
329
+ });
330
+ ```
331
+
332
+ Para remover um listener:
333
+
334
+ ```typescript
335
+ const handler = (call) => console.log(call);
336
+ client.on('call:incoming', handler);
337
+ client.off('call:incoming', handler);
338
+ ```
339
+
340
+ ## Widget
341
+
342
+ O widget é criado automaticamente quando `autoWidget` está ativo (default). Ele renderiza dentro de um Shadow DOM isolado, sem conflitos de CSS com a aplicação host.
343
+
344
+ ### Estrutura
345
+
346
+ O widget possui 3 views:
347
+
348
+ **Discador** — Teclado numérico para digitar e iniciar chamadas.
349
+
350
+ **Chamadas** — Lista de chamadas ativas com botões de aceitar/rejeitar/encerrar.
351
+
352
+ **Ligação Ativa** — Tela fullscreen (no painel) com avatar, número, timer, barra de áudio e controles de mute/encerrar.
353
+
354
+ ### Comportamento Automático
355
+
356
+ - Abre o painel automaticamente ao receber uma chamada
357
+ - Muda para a view "Chamadas" quando tem chamada entrando
358
+ - Muda para a view "Ligação Ativa" quando a chamada é aceita
359
+ - Volta para "Discador" quando todas as chamadas encerram
360
+ - Badge no bubble mostra número de chamadas ativas
361
+ - Dot verde/vermelho indica status da conexão
362
+ - Pulse animation no bubble quando tem chamada tocando
363
+
364
+ ### Modo Headless
365
+
366
+ Para controlar tudo manualmente sem widget:
367
+
368
+ ```typescript
369
+ const client = init({
370
+ instanceId: '...',
371
+ getToken: async () => { /* ... */ },
372
+ autoWidget: false,
373
+ });
374
+
375
+ // Gerencie chamadas via API
376
+ client.on('call:incoming', (call) => {
377
+ // Sua UI customizada
378
+ });
379
+ ```
380
+
381
+ ## Tipos
382
+
383
+ ```typescript
384
+ interface CallInfo {
385
+ callId: string; // ID único da chamada
386
+ from: string; // Número de origem
387
+ isVideo: boolean; // Se é vídeo chamada
388
+ isGroup: boolean; // Se é chamada de grupo
389
+ state: CallState; // Estado atual
390
+ timestamp: number; // Timestamp de início
391
+ }
392
+
393
+ type CallState = 'ringing' | 'preaccepted' | 'accepted' | 'active' | 'ended';
394
+
395
+ type WidgetPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
396
+
397
+ type ThemeMode = 'dark' | 'light';
398
+
399
+ interface AudioConfig {
400
+ sampleRate: number; // Taxa de amostragem (ex: 16000)
401
+ channels: number; // Canais de áudio (1 = mono)
402
+ }
403
+ ```
404
+
405
+ ## Protocolo WebSocket
406
+
407
+ A SDK se conecta automaticamente ao servidor via WebSocket e gerencia reconexão com backoff exponencial. O token efêmero obtido via `getToken` é utilizado em cada conexão/reconexão.
408
+
409
+ ### URL de Conexão
410
+
411
+ ```
412
+ wss://call.z-api.io/ws/call?instance=SUA_INSTANCE_ID&token=TOKEN_EFEMERO
413
+ ```
414
+
415
+ ### Mensagens Client -> Server
416
+
417
+ | Tipo | Payload | Descrição |
418
+ |------|---------|-----------|
419
+ | `call:accept` | `{ callId }` | Aceitar chamada |
420
+ | `call:reject` | `{ callId }` | Rejeitar/encerrar chamada |
421
+ | `call:mute` | `{ muted }` | Mutar/desmutar mic |
422
+ | `call:camera` | `{ enabled }` | Ligar/desligar câmera (upgrade para vídeo se necessário) |
423
+ | `call:make` | `{ number, isVideo? }` | Iniciar chamada de saída (áudio ou vídeo) |
424
+ | `ping` | `{}` | Keep-alive (automático, 25s) |
425
+ | *binary 0x01* | `ArrayBuffer` | Áudio PCM Int16LE do microfone |
426
+ | *binary 0x02* | `ArrayBuffer` | Frame de vídeo NV12 (width u16 + height u16 + data) |
427
+
428
+ ### Mensagens Server -> Client
429
+
430
+ | Tipo | Payload | Descrição |
431
+ |------|---------|-----------|
432
+ | `connected` | `{ instanceId, sdkId, audioConfig }` | Conexão estabelecida |
433
+ | `call:incoming` | `{ callId, from, isVideo, isGroup, state?, timestamp }` | Chamada recebida |
434
+ | `call:outgoing` | `{ callId, to, isVideo }` | Chamada de saída iniciada |
435
+ | `call:state` | `{ callId, state }` | Mudança de estado |
436
+ | `call:video-state` | `{ callId, isVideo }` | Vídeo ativado/desativado durante chamada |
437
+ | `call:terminated` | `{ callId, reason? }` | Chamada encerrada |
438
+ | `call:claimed` | `{ callId }` | Chamada aceita por outro cliente |
439
+ | `call:dismissed` | `{ callId }` | Chamada rejeitada por outro cliente |
440
+ | `pong` | `{ ts }` | Resposta ao ping |
441
+ | `error` | `{ command, message }` | Erro de processamento |
442
+ | *binary 0x00* | `ArrayBuffer` | Áudio PCM Int16LE para playback |
443
+ | *binary 0x01* | `ArrayBuffer` | Frame de vídeo (header 16 bytes + pixel data) |
444
+
445
+ ## Áudio
446
+
447
+ A SDK gerencia captura e reprodução de áudio automaticamente:
448
+
449
+ - **Formato:** PCM Int16LE, mono
450
+ - **Sample rate:** Configurável pelo servidor (default: 16000 Hz)
451
+ - **Captura:** Microfone com echo cancellation, noise suppression e auto gain
452
+ - **Playback:** Web Audio API com scheduling otimizado
453
+ - **Permissão:** O microfone é solicitado automaticamente ao aceitar uma chamada
454
+
455
+ > **Importante:** Navegadores exigem interação do usuário antes de reproduzir áudio. A SDK chama `AudioContext.resume()` automaticamente quando o usuário clica no widget.
456
+
457
+ ## Vídeo
458
+
459
+ A SDK suporta chamadas de vídeo e upgrade de áudio para vídeo durante a chamada:
460
+
461
+ - **Formato de recepção:** NV12 com header (width, height, format, orientation, keyframe, timestamp)
462
+ - **Formato de envio:** NV12 (RGBA capturado da câmera, convertido para NV12 no browser)
463
+ - **Renderização:** WebCodecs API (hardware-accelerated) com fallback para software
464
+ - **Câmera:** Captura a 320x240 @ 30fps (default)
465
+ - **Orientação:** Suporte a rotação 0/90/180/270 graus
466
+
467
+ ### Fluxos suportados
468
+
469
+ | Cenário | Comportamento |
470
+ |---------|--------------|
471
+ | Chamada inicia como vídeo | Câmera liga automaticamente ao aceitar |
472
+ | Chamada inicia como áudio, peer muda para vídeo | Vídeo remoto é exibido, câmera liga pelo botão |
473
+ | Chamada inicia como áudio, usuário muda para vídeo | Clica no botão de câmera, envia upgrade request ao peer |
474
+ | Discador com botão de vídeo | Habilitado via `showVideoDialButton: true` |
475
+
476
+ ## Exemplos
477
+
478
+ ### Integração Básica
479
+
480
+ ```html
481
+ <!DOCTYPE html>
482
+ <html>
483
+ <head>
484
+ <title>Meu Webphone</title>
485
+ </head>
486
+ <body>
487
+ <h1>Minha Aplicação</h1>
488
+ <script src="https://unpkg.com/@z-api/call/dist/z-api-call.global.js"></script>
489
+ <script>
490
+ const client = ZAPICall.init({
491
+ instanceId: 'minha-instancia',
492
+ getToken: async () => {
493
+ const res = await fetch('https://seu-backend.com/call-token');
494
+ const data = await res.json();
495
+ return data.token;
496
+ },
497
+ theme: { mode: 'light' },
498
+ });
499
+ </script>
500
+ </body>
501
+ </html>
502
+ ```
503
+
504
+ ### React
505
+
506
+ ```tsx
507
+ import { useEffect, useRef } from 'react';
508
+ import { init, ZAPICallClient } from '@z-api/call';
509
+
510
+ function App() {
511
+ const clientRef = useRef<ZAPICallClient | null>(null);
512
+
513
+ useEffect(() => {
514
+ const client = init({
515
+ instanceId: 'minha-instancia',
516
+ getToken: async () => {
517
+ const res = await fetch('/api/call-token');
518
+ const { token } = await res.json();
519
+ return token;
520
+ },
521
+ position: 'bottom-left',
522
+ theme: { mode: 'dark', primaryColor: '#7c3aed' },
523
+ onIncomingCall: (call) => {
524
+ console.log('Chamada de', call.from);
525
+ },
526
+ });
527
+
528
+ clientRef.current = client;
529
+ return () => client.destroy();
530
+ }, []);
531
+
532
+ return <div>Minha App</div>;
533
+ }
534
+ ```
535
+
536
+ ### Headless com UI Customizada
537
+
538
+ ```typescript
539
+ import { init } from '@z-api/call';
540
+
541
+ const client = init({
542
+ instanceId: '...',
543
+ getToken: async () => {
544
+ const res = await fetch('/api/call-token');
545
+ const { token } = await res.json();
546
+ return token;
547
+ },
548
+ autoWidget: false,
549
+ });
550
+
551
+ client.on('connected', () => {
552
+ document.getElementById('status')!.textContent = 'Online';
553
+ });
554
+
555
+ client.on('call:incoming', (call) => {
556
+ const accept = confirm(`Chamada de ${call.from}. Aceitar?`);
557
+ if (accept) {
558
+ client.accept(call.callId);
559
+ } else {
560
+ client.reject(call.callId);
561
+ }
562
+ });
563
+
564
+ client.on('call:state', (callId, state) => {
565
+ document.getElementById('call-state')!.textContent = state;
566
+ });
567
+
568
+ client.on('audio:level', (level) => {
569
+ document.getElementById('meter')!.style.width = `${level * 100}%`;
570
+ });
571
+ ```
572
+
573
+ ## Compatibilidade
574
+
575
+ - Chrome 80+
576
+ - Firefox 78+
577
+ - Safari 14+
578
+ - Edge 80+
579
+
580
+ Requer suporte a:
581
+ - WebSocket
582
+ - Web Audio API
583
+ - getUserMedia (para microfone e câmera)
584
+ - Shadow DOM
585
+ - Canvas 2D (para renderização de vídeo)
586
+ - WebCodecs API (opcional, para renderização acelerada por hardware)
587
+
588
+ ## Licença
589
+
590
+ Proprietary - Four Pixel IT
@@ -0,0 +1,25 @@
1
+ export type OnMicData = (pcmInt16: ArrayBuffer) => void;
2
+ export type OnAudioLevel = (level: number) => void;
3
+ export declare class AudioEngine {
4
+ private playbackCtx;
5
+ private micCtx;
6
+ private micStream;
7
+ private micProcessor;
8
+ private micSource;
9
+ private nextPlayTime;
10
+ private sampleRate;
11
+ private destroyed;
12
+ onMicData: OnMicData;
13
+ onAudioLevel: OnAudioLevel;
14
+ constructor(sampleRate?: number);
15
+ /** Play received PCM Int16LE audio */
16
+ private playLogCount;
17
+ playPcm(data: ArrayBuffer): void;
18
+ /** Start capturing microphone audio and sending as PCM Int16LE */
19
+ startMic(): Promise<void>;
20
+ stopMic(): void;
21
+ /** Resume AudioContext (must be called from user gesture for autoplay policy) */
22
+ resume(): void;
23
+ destroy(): void;
24
+ }
25
+ //# sourceMappingURL=AudioEngine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AudioEngine.d.ts","sourceRoot":"","sources":["../../src/core/AudioEngine.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,SAAS,GAAG,CAAC,QAAQ,EAAE,WAAW,KAAK,IAAI,CAAC;AACxD,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;AAEnD,qBAAa,WAAW;IACtB,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,YAAY,CAAoC;IACxD,OAAO,CAAC,SAAS,CAA2C;IAC5D,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAS;IAE1B,SAAS,EAAE,SAAS,CAAY;IAChC,YAAY,EAAE,YAAY,CAAY;gBAE1B,UAAU,SAAQ;IAI9B,sCAAsC;IACtC,OAAO,CAAC,YAAY,CAAK;IAEzB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IAgDhC,kEAAkE;IAC5D,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA6B/B,OAAO,IAAI,IAAI;IAqBf,iFAAiF;IACjF,MAAM,IAAI,IAAI;IAUd,OAAO,IAAI,IAAI;CAQhB"}
@@ -0,0 +1,15 @@
1
+ import type { CallInfo, CallState } from '../types';
2
+ export declare class CallStateManager {
3
+ private calls;
4
+ addCall(call: CallInfo): void;
5
+ updateState(callId: string, state: CallState): void;
6
+ updateIsVideo(callId: string, isVideo: boolean): void;
7
+ removeCall(callId: string): void;
8
+ getCall(callId: string): CallInfo | undefined;
9
+ getActiveCall(): CallInfo | undefined;
10
+ getRingingCalls(): CallInfo[];
11
+ getAllCalls(): CallInfo[];
12
+ hasActiveCalls(): boolean;
13
+ clear(): void;
14
+ }
15
+ //# sourceMappingURL=CallState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CallState.d.ts","sourceRoot":"","sources":["../../src/core/CallState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAEpD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,KAAK,CAA+B;IAE5C,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAI7B,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI;IASnD,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAOrD,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIhC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAI7C,aAAa,IAAI,QAAQ,GAAG,SAAS;IASrC,eAAe,IAAI,QAAQ,EAAE;IAU7B,WAAW,IAAI,QAAQ,EAAE;IAIzB,cAAc,IAAI,OAAO;IAOzB,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,29 @@
1
+ import type { WsServerMessage } from '../types';
2
+ export type OnJsonMessage = (msg: WsServerMessage) => void;
3
+ export type OnBinaryMessage = (data: ArrayBuffer) => void;
4
+ export type OnConnectionChange = (connected: boolean) => void;
5
+ export declare class CallWebSocket {
6
+ private ws;
7
+ private baseUrl;
8
+ private instanceId;
9
+ private getToken;
10
+ private reconnectMs;
11
+ private reconnectTimer;
12
+ private pingTimer;
13
+ private destroyed;
14
+ onJson: OnJsonMessage;
15
+ onBinary: OnBinaryMessage;
16
+ onConnectionChange: OnConnectionChange;
17
+ constructor(baseUrl: string, instanceId: string, getToken: () => Promise<string>);
18
+ private buildUrl;
19
+ connect(): Promise<void>;
20
+ send(data: string | ArrayBuffer): void;
21
+ sendJson(msg: Record<string, unknown>): void;
22
+ isConnected(): boolean;
23
+ destroy(): void;
24
+ private cleanup;
25
+ private scheduleReconnect;
26
+ private startPing;
27
+ private stopPing;
28
+ }
29
+ //# sourceMappingURL=CallWebSocket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CallWebSocket.d.ts","sourceRoot":"","sources":["../../src/core/CallWebSocket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhD,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;AAC3D,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;AAC1D,MAAM,MAAM,kBAAkB,GAAG,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;AAM9D,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,SAAS,CAA+C;IAChE,OAAO,CAAC,SAAS,CAAS;IAE1B,MAAM,EAAE,aAAa,CAAY;IACjC,QAAQ,EAAE,eAAe,CAAY;IACrC,kBAAkB,EAAE,kBAAkB,CAAY;gBAEtC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC;IAMhF,OAAO,CAAC,QAAQ;IASV,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAyD9B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAMtC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI5C,WAAW,IAAI,OAAO;IAItB,OAAO,IAAI,IAAI;IASf,OAAO,CAAC,OAAO;IAcf,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,QAAQ;CAMjB"}
@@ -0,0 +1,12 @@
1
+ type Listener = (...args: any[]) => void;
2
+ export declare class EventEmitter<Events extends {
3
+ [K in keyof Events]: Listener;
4
+ }> {
5
+ private listeners;
6
+ on<K extends keyof Events>(event: K, listener: Events[K]): this;
7
+ off<K extends keyof Events>(event: K, listener: Events[K]): this;
8
+ protected emit<K extends keyof Events>(event: K, ...args: Parameters<Events[K]>): void;
9
+ removeAllListeners(): void;
10
+ }
11
+ export {};
12
+ //# sourceMappingURL=EventEmitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventEmitter.d.ts","sourceRoot":"","sources":["../../src/core/EventEmitter.ts"],"names":[],"mappings":"AAAA,KAAK,QAAQ,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;AAEzC,qBAAa,YAAY,CAAC,MAAM,SAAS;KAAG,CAAC,IAAI,MAAM,MAAM,GAAG,QAAQ;CAAE;IACxE,OAAO,CAAC,SAAS,CAA0C;IAE3D,EAAE,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI;IAQ/D,GAAG,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI;IAKhE,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAYtF,kBAAkB,IAAI,IAAI;CAG3B"}