dvgateway-sdk 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.
Files changed (78) hide show
  1. package/README.md +615 -0
  2. package/dist/audio/codec.d.ts +44 -0
  3. package/dist/audio/codec.d.ts.map +1 -0
  4. package/dist/audio/codec.js +136 -0
  5. package/dist/audio/codec.js.map +1 -0
  6. package/dist/audio/codec.test.d.ts +2 -0
  7. package/dist/audio/codec.test.d.ts.map +1 -0
  8. package/dist/audio/codec.test.js +155 -0
  9. package/dist/audio/codec.test.js.map +1 -0
  10. package/dist/auth/manager.d.ts +34 -0
  11. package/dist/auth/manager.d.ts.map +1 -0
  12. package/dist/auth/manager.js +122 -0
  13. package/dist/auth/manager.js.map +1 -0
  14. package/dist/auth/manager.test.d.ts +2 -0
  15. package/dist/auth/manager.test.d.ts.map +1 -0
  16. package/dist/auth/manager.test.js +147 -0
  17. package/dist/auth/manager.test.js.map +1 -0
  18. package/dist/client.d.ts +154 -0
  19. package/dist/client.d.ts.map +1 -0
  20. package/dist/client.js +218 -0
  21. package/dist/client.js.map +1 -0
  22. package/dist/index.d.ts +36 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +40 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/minutes/manager.d.ts +43 -0
  27. package/dist/minutes/manager.d.ts.map +1 -0
  28. package/dist/minutes/manager.js +71 -0
  29. package/dist/minutes/manager.js.map +1 -0
  30. package/dist/observability/logger.d.ts +19 -0
  31. package/dist/observability/logger.d.ts.map +1 -0
  32. package/dist/observability/logger.js +70 -0
  33. package/dist/observability/logger.js.map +1 -0
  34. package/dist/observability/metrics.d.ts +53 -0
  35. package/dist/observability/metrics.d.ts.map +1 -0
  36. package/dist/observability/metrics.js +143 -0
  37. package/dist/observability/metrics.js.map +1 -0
  38. package/dist/observability/metrics.test.d.ts +2 -0
  39. package/dist/observability/metrics.test.d.ts.map +1 -0
  40. package/dist/observability/metrics.test.js +122 -0
  41. package/dist/observability/metrics.test.js.map +1 -0
  42. package/dist/pipeline/builder.d.ts +111 -0
  43. package/dist/pipeline/builder.d.ts.map +1 -0
  44. package/dist/pipeline/builder.js +323 -0
  45. package/dist/pipeline/builder.js.map +1 -0
  46. package/dist/session/manager.d.ts +21 -0
  47. package/dist/session/manager.d.ts.map +1 -0
  48. package/dist/session/manager.js +52 -0
  49. package/dist/session/manager.js.map +1 -0
  50. package/dist/streams/audio-stream.d.ts +29 -0
  51. package/dist/streams/audio-stream.d.ts.map +1 -0
  52. package/dist/streams/audio-stream.js +118 -0
  53. package/dist/streams/audio-stream.js.map +1 -0
  54. package/dist/streams/call-events.d.ts +32 -0
  55. package/dist/streams/call-events.d.ts.map +1 -0
  56. package/dist/streams/call-events.js +140 -0
  57. package/dist/streams/call-events.js.map +1 -0
  58. package/dist/streams/tts-stream.d.ts +46 -0
  59. package/dist/streams/tts-stream.d.ts.map +1 -0
  60. package/dist/streams/tts-stream.js +102 -0
  61. package/dist/streams/tts-stream.js.map +1 -0
  62. package/dist/transport/http-client.d.ts +36 -0
  63. package/dist/transport/http-client.d.ts.map +1 -0
  64. package/dist/transport/http-client.js +102 -0
  65. package/dist/transport/http-client.js.map +1 -0
  66. package/dist/transport/http-client.test.d.ts +2 -0
  67. package/dist/transport/http-client.test.d.ts.map +1 -0
  68. package/dist/transport/http-client.test.js +172 -0
  69. package/dist/transport/http-client.test.js.map +1 -0
  70. package/dist/transport/ws-pool.d.ts +34 -0
  71. package/dist/transport/ws-pool.d.ts.map +1 -0
  72. package/dist/transport/ws-pool.js +123 -0
  73. package/dist/transport/ws-pool.js.map +1 -0
  74. package/dist/types/index.d.ts +378 -0
  75. package/dist/types/index.d.ts.map +1 -0
  76. package/dist/types/index.js +25 -0
  77. package/dist/types/index.js.map +1 -0
  78. package/package.json +81 -0
@@ -0,0 +1,323 @@
1
+ /**
2
+ * VoiceAI Pipeline Builder
3
+ *
4
+ * High-level fluent API for wiring STT → LLM → TTS pipelines.
5
+ * Handles the entire lifecycle: call events, audio streaming, AI processing,
6
+ * and TTS injection — all with a single .start() call.
7
+ *
8
+ * Architecture (2026 cascaded pipeline pattern):
9
+ *
10
+ * Inbound call
11
+ * ↓
12
+ * AudioStream (WebSocket, slin16 → Float32)
13
+ * ↓
14
+ * [VAD filter] (optional, reduces STT API cost)
15
+ * ↓
16
+ * SttAdapter.startStream() → onTranscript(isFinal=true)
17
+ * ↓
18
+ * LlmAdapter.chat() → streaming tokens
19
+ * ↓ (first token triggers TTS immediately)
20
+ * TtsAdapter.synthesize() → PCM chunks
21
+ * ↓
22
+ * TtsInjector.injectStreaming()
23
+ * ↓
24
+ * Call audio (Asterisk)
25
+ *
26
+ * Latency budget target: <500ms end-to-end (STT ~200ms, LLM TTFT ~80ms, TTS TTFA ~150ms)
27
+ */
28
+ import { createAudioStream } from '../streams/audio-stream.js';
29
+ // ─── Fallback wrapper ──────────────────────────────────────────────────────
30
+ class WithFallback {
31
+ primary;
32
+ fallback;
33
+ constructor(primary, fallback) {
34
+ this.primary = primary;
35
+ this.fallback = fallback;
36
+ }
37
+ }
38
+ class SttStage {
39
+ _adapter;
40
+ _fallback;
41
+ _builder;
42
+ constructor(_adapter, _fallback, _builder) {
43
+ this._adapter = _adapter;
44
+ this._fallback = _fallback;
45
+ this._builder = _builder;
46
+ }
47
+ fallback(adapter) {
48
+ this._fallback = adapter;
49
+ return this;
50
+ }
51
+ toWrapped() {
52
+ return new WithFallback(this._adapter, this._fallback);
53
+ }
54
+ llm(adapter) {
55
+ return this._builder['setLlm'](adapter, this.toWrapped());
56
+ }
57
+ // Conference mode: skip LLM, just emit transcripts
58
+ forConference() {
59
+ return new ConferencePipelineBuilder(this._builder, this.toWrapped());
60
+ }
61
+ }
62
+ class LlmStage {
63
+ _adapter;
64
+ _fallback;
65
+ _stt;
66
+ _builder;
67
+ constructor(_adapter, _fallback, _stt, _builder) {
68
+ this._adapter = _adapter;
69
+ this._fallback = _fallback;
70
+ this._stt = _stt;
71
+ this._builder = _builder;
72
+ }
73
+ fallback(adapter) {
74
+ this._fallback = adapter;
75
+ return this;
76
+ }
77
+ tts(adapter) {
78
+ return this._builder['setTts'](adapter, this._stt, this.toWrapped());
79
+ }
80
+ toWrapped() {
81
+ return new WithFallback(this._adapter, this._fallback);
82
+ }
83
+ }
84
+ class TtsStage {
85
+ _adapter;
86
+ _fallback;
87
+ _stt;
88
+ _llm;
89
+ _builder;
90
+ constructor(_adapter, _fallback, _stt, _llm, _builder) {
91
+ this._adapter = _adapter;
92
+ this._fallback = _fallback;
93
+ this._stt = _stt;
94
+ this._llm = _llm;
95
+ this._builder = _builder;
96
+ }
97
+ fallback(adapter) {
98
+ this._fallback = adapter;
99
+ return this;
100
+ }
101
+ audioFilter(opts) {
102
+ this._builder['_dir'] = opts.dir;
103
+ return this;
104
+ }
105
+ onNewCall(handler) {
106
+ this._builder['_onNewCall'] = handler;
107
+ return this;
108
+ }
109
+ onCallEnded(handler) {
110
+ this._builder['_onCallEnded'] = handler;
111
+ return this;
112
+ }
113
+ onTranscript(handler) {
114
+ this._builder['_onTranscript'] = handler;
115
+ return this;
116
+ }
117
+ onError(handler) {
118
+ this._builder['_onError'] = handler;
119
+ return this;
120
+ }
121
+ async start() {
122
+ return this._builder['startPipeline'](this._stt, this._llm, new WithFallback(this._adapter, this._fallback));
123
+ }
124
+ async stop() {
125
+ return this._builder['stopPipeline']();
126
+ }
127
+ }
128
+ // ─── Conference Pipeline (STT-only, no LLM/TTS) ───────────────────────────
129
+ export class ConferencePipelineBuilder {
130
+ _builder;
131
+ _stt;
132
+ _onTranscript;
133
+ _onError;
134
+ constructor(_builder, _stt) {
135
+ this._builder = _builder;
136
+ this._stt = _stt;
137
+ }
138
+ onTranscript(handler) {
139
+ this._onTranscript = handler;
140
+ return this;
141
+ }
142
+ onError(handler) {
143
+ this._onError = handler;
144
+ return this;
145
+ }
146
+ async start() {
147
+ return this._builder['startConferencePipeline'](this._stt, this._onTranscript, this._onError);
148
+ }
149
+ }
150
+ // ─── Main Builder ──────────────────────────────────────────────────────────
151
+ export class PipelineBuilder {
152
+ wsPool;
153
+ callEvents;
154
+ ttsInjector;
155
+ logger;
156
+ // Private state (accessed by inner stages via string indexing above)
157
+ _dir = 'both';
158
+ _onNewCall;
159
+ _onCallEnded;
160
+ _onTranscript;
161
+ _onError;
162
+ _activeCalls = new Map();
163
+ _running = false;
164
+ constructor(wsPool, callEvents, ttsInjector, logger) {
165
+ this.wsPool = wsPool;
166
+ this.callEvents = callEvents;
167
+ this.ttsInjector = ttsInjector;
168
+ this.logger = logger;
169
+ }
170
+ /** Set the STT adapter (first step in fluent chain) */
171
+ stt(adapter) {
172
+ return new SttStage(adapter, undefined, this);
173
+ }
174
+ // ── Internal stage setters (called by stage classes) ────────────────────
175
+ setLlm(adapter, stt) {
176
+ return new LlmStage(adapter, undefined, stt, this);
177
+ }
178
+ setTts(adapter, stt, llm) {
179
+ return new TtsStage(adapter, undefined, stt, llm, this);
180
+ }
181
+ // ── Full STT → LLM → TTS pipeline ───────────────────────────────────────
182
+ async startPipeline(stt, llm, tts) {
183
+ if (this._running)
184
+ throw new Error('Pipeline is already running. Call stop() first.');
185
+ this._running = true;
186
+ const systemPrompt = llm.primary.systemPrompt ??
187
+ 'You are a helpful voice assistant. Keep answers concise and conversational.';
188
+ const unsubscribe = this.callEvents.on(async (event) => {
189
+ if (event.type === 'call:new') {
190
+ const { session } = event;
191
+ this.logger.info({ linkedId: session.linkedId }, 'New call — starting AI pipeline');
192
+ await this._onNewCall?.(session);
193
+ void this.handleCall(session, stt, llm, tts, systemPrompt);
194
+ }
195
+ if (event.type === 'call:ended') {
196
+ const state = this._activeCalls.get(event.linkedId);
197
+ if (state) {
198
+ state.audioStreamUnsubscribe();
199
+ await state.sttAdapter.stop();
200
+ this._activeCalls.delete(event.linkedId);
201
+ }
202
+ await this._onCallEnded?.(event.linkedId, event.durationSec);
203
+ this.logger.info({ linkedId: event.linkedId, duration: event.durationSec }, 'Call ended');
204
+ }
205
+ });
206
+ // Keep pipeline alive — return a never-resolving promise that
207
+ // resolves when stop() is called
208
+ return new Promise((resolve) => {
209
+ this.wsPool.once('__pipelineStop', () => {
210
+ unsubscribe();
211
+ resolve();
212
+ });
213
+ });
214
+ }
215
+ async handleCall(session, stt, llm, tts, systemPrompt) {
216
+ const conversationHistory = [
217
+ { role: 'system', content: systemPrompt },
218
+ ];
219
+ // Create audio stream
220
+ const audioStream = createAudioStream(this.wsPool, session.linkedId, this.logger, { dir: this._dir });
221
+ // Choose STT adapter (try primary, fall back on error)
222
+ const sttAdapter = stt.primary;
223
+ const state = {
224
+ session,
225
+ conversationHistory,
226
+ sttAdapter,
227
+ audioStreamUnsubscribe: () => audioStream.unsubscribe(),
228
+ };
229
+ this._activeCalls.set(session.linkedId, state);
230
+ // Register transcript handler before starting stream
231
+ sttAdapter.onTranscript(async (result) => {
232
+ if (!result.isFinal)
233
+ return; // Ignore partials in pipeline
234
+ await this._onTranscript?.(result, session);
235
+ this.logger.debug({ linkedId: session.linkedId }, 'Transcript finalized, calling LLM');
236
+ // Append user utterance to conversation
237
+ conversationHistory.push({ role: 'user', content: result.text });
238
+ // LLM call (with fallback)
239
+ try {
240
+ let responseText = '';
241
+ const llmAdapter = llm.primary;
242
+ // Stream tokens and accumulate
243
+ for await (const token of llmAdapter.chat(conversationHistory)) {
244
+ responseText += token;
245
+ // First-token trigger: start TTS immediately when we have enough text
246
+ if (responseText.length === token.length && token.length > 0) {
247
+ this.logger.debug({ linkedId: session.linkedId }, 'LLM first token received, starting TTS');
248
+ }
249
+ }
250
+ if (!responseText)
251
+ return;
252
+ // Append assistant response to history
253
+ conversationHistory.push({ role: 'assistant', content: responseText });
254
+ // TTS synthesis and injection (streamed)
255
+ const ttsAdapter = tts.primary;
256
+ const audioChunks = ttsAdapter.synthesize(responseText);
257
+ await this.ttsInjector.injectStreaming(session.linkedId, audioChunks);
258
+ }
259
+ catch (err) {
260
+ const error = err instanceof Error ? err : new Error(String(err));
261
+ this.logger.error({ err: error.message, linkedId: session.linkedId }, 'Pipeline error');
262
+ await this._onError?.(error, session.linkedId);
263
+ }
264
+ });
265
+ // Start STT stream (this will run until audioStream ends)
266
+ try {
267
+ await sttAdapter.startStream(session.linkedId, audioStream);
268
+ }
269
+ catch (err) {
270
+ const error = err instanceof Error ? err : new Error(String(err));
271
+ this.logger.error({ err: error.message, linkedId: session.linkedId }, 'STT stream error');
272
+ await this._onError?.(error, session.linkedId);
273
+ }
274
+ }
275
+ // ── Conference STT-only pipeline ─────────────────────────────────────────
276
+ async startConferencePipeline(stt, onTranscript, onError) {
277
+ if (this._running)
278
+ throw new Error('Pipeline is already running.');
279
+ this._running = true;
280
+ const unsubscribe = this.callEvents.on(async (event) => {
281
+ if (event.type === 'call:new' || event.type === 'conf:join') {
282
+ const linkedId = event.type === 'call:new' ? event.session.linkedId : event.linkedId;
283
+ const fakeSession = event.type === 'call:new'
284
+ ? event.session
285
+ : { linkedId, confId: event.confId, dir: 'both', startedAt: new Date(), streamUrl: '' };
286
+ const audioStream = createAudioStream(this.wsPool, linkedId, this.logger, { dir: this._dir });
287
+ const sttAdapter = stt.primary;
288
+ sttAdapter.onTranscript(async (result) => {
289
+ await onTranscript?.(result, fakeSession);
290
+ });
291
+ sttAdapter.startStream(linkedId, audioStream).catch(async (err) => {
292
+ const error = err instanceof Error ? err : new Error(String(err));
293
+ await onError?.(error, linkedId);
294
+ });
295
+ }
296
+ if (event.type === 'call:ended' || event.type === 'conf:leave') {
297
+ const linkedId = event.type === 'call:ended' ? event.linkedId : event.linkedId;
298
+ const state = this._activeCalls.get(linkedId);
299
+ if (state) {
300
+ state.audioStreamUnsubscribe();
301
+ await state.sttAdapter.stop();
302
+ this._activeCalls.delete(linkedId);
303
+ }
304
+ }
305
+ });
306
+ return new Promise((resolve) => {
307
+ this.wsPool.once('__pipelineStop', () => {
308
+ unsubscribe();
309
+ resolve();
310
+ });
311
+ });
312
+ }
313
+ stopPipeline() {
314
+ this._running = false;
315
+ for (const [, state] of this._activeCalls) {
316
+ state.audioStreamUnsubscribe();
317
+ void state.sttAdapter.stop();
318
+ }
319
+ this._activeCalls.clear();
320
+ this.wsPool.emit('__pipelineStop');
321
+ }
322
+ }
323
+ //# sourceMappingURL=builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/pipeline/builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAeH,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAG/D,8EAA8E;AAE9E,MAAM,YAAY;IAEE;IACA;IAFlB,YACkB,OAAU,EACV,QAAY;QADZ,YAAO,GAAP,OAAO,CAAG;QACV,aAAQ,GAAR,QAAQ,CAAI;IAC3B,CAAC;CACL;AAiBD,MAAM,QAAQ;IAEO;IACT;IACS;IAHnB,YACmB,QAAoB,EAC7B,SAAiC,EACxB,QAAyB;QAFzB,aAAQ,GAAR,QAAQ,CAAY;QAC7B,cAAS,GAAT,SAAS,CAAwB;QACxB,aAAQ,GAAR,QAAQ,CAAiB;IACzC,CAAC;IAEJ,QAAQ,CAAC,OAAmB;QAC1B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,SAAS;QACP,OAAO,IAAI,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACzD,CAAC;IAED,GAAG,CAAC,OAAmB;QACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,mDAAmD;IACnD,aAAa;QACX,OAAO,IAAI,yBAAyB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IACxE,CAAC;CACF;AAED,MAAM,QAAQ;IAEO;IACT;IACS;IACA;IAJnB,YACmB,QAAoB,EAC7B,SAAiC,EACxB,IAA8B,EAC9B,QAAyB;QAHzB,aAAQ,GAAR,QAAQ,CAAY;QAC7B,cAAS,GAAT,SAAS,CAAwB;QACxB,SAAI,GAAJ,IAAI,CAA0B;QAC9B,aAAQ,GAAR,QAAQ,CAAiB;IACzC,CAAC;IAEJ,QAAQ,CAAC,OAAmB;QAC1B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,GAAG,CAAC,OAAmB;QACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,SAAS;QACP,OAAO,IAAI,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACzD,CAAC;CACF;AAED,MAAM,QAAQ;IAEO;IACT;IACS;IACA;IACA;IALnB,YACmB,QAAoB,EAC7B,SAAiC,EACxB,IAA8B,EAC9B,IAA8B,EAC9B,QAAyB;QAJzB,aAAQ,GAAR,QAAQ,CAAY;QAC7B,cAAS,GAAT,SAAS,CAAwB;QACxB,SAAI,GAAJ,IAAI,CAA0B;QAC9B,SAAI,GAAJ,IAAI,CAA0B;QAC9B,aAAQ,GAAR,QAAQ,CAAiB;IACzC,CAAC;IAEJ,QAAQ,CAAC,OAAmB;QAC1B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,WAAW,CAAC,IAAwB;QAClC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,SAAS,CAAC,OAAuD;QAC/D,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,WAAW,CAAC,OAAwE;QAClF,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,YAAY,CAAC,OAAiF;QAC5F,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC;QACzC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CAAC,OAAgE;QACtE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,KAAK;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,CACnC,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,IAAI,EACT,IAAI,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAChD,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAAI;QACR,OAAO,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;IACzC,CAAC;CACF;AAED,6EAA6E;AAE7E,MAAM,OAAO,yBAAyB;IAKjB;IACA;IALX,aAAa,CAA4E;IACzF,QAAQ,CAA2D;IAE3E,YACmB,QAAyB,EACzB,IAA8B;QAD9B,aAAQ,GAAR,QAAQ,CAAiB;QACzB,SAAI,GAAJ,IAAI,CAA0B;IAC9C,CAAC;IAEJ,YAAY,CAAC,OAAiF;QAC5F,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CAAC,OAAgE;QACtE,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,KAAK;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAC7C,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,QAAQ,CACd,CAAC;IACJ,CAAC;CACF;AAED,8EAA8E;AAE9E,MAAM,OAAO,eAAe;IAWP;IACA;IACA;IACA;IAbnB,qEAAqE;IAC7D,IAAI,GAAc,MAAM,CAAC;IACzB,UAAU,CAAkD;IAC5D,YAAY,CAAmE;IAC/E,aAAa,CAA4E;IACzF,QAAQ,CAA2D;IACnE,YAAY,GAAG,IAAI,GAAG,EAA6B,CAAC;IACpD,QAAQ,GAAG,KAAK,CAAC;IAEzB,YACmB,MAAc,EACd,UAA2B,EAC3B,WAAwB,EACxB,MAAc;QAHd,WAAM,GAAN,MAAM,CAAQ;QACd,eAAU,GAAV,UAAU,CAAiB;QAC3B,gBAAW,GAAX,WAAW,CAAa;QACxB,WAAM,GAAN,MAAM,CAAQ;IAC9B,CAAC;IAEJ,uDAAuD;IACvD,GAAG,CAAC,OAAmB;QACrB,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAChD,CAAC;IAED,2EAA2E;IAEnE,MAAM,CACZ,OAAmB,EACnB,GAA6B;QAE7B,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IACrD,CAAC;IAEO,MAAM,CACZ,OAAmB,EACnB,GAA6B,EAC7B,GAA6B;QAE7B,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC1D,CAAC;IAED,2EAA2E;IAEnE,KAAK,CAAC,aAAa,CACzB,GAA6B,EAC7B,GAA6B,EAC7B,GAA6B;QAE7B,IAAI,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACtF,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,MAAM,YAAY,GACf,GAAG,CAAC,OAAgD,CAAC,YAAY;YAClE,6EAA6E,CAAC;QAEhF,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACrD,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC9B,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;gBAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,iCAAiC,CAAC,CAAC;gBACpF,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC,OAAO,CAAC,CAAC;gBACjC,KAAK,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;YAC7D,CAAC;YAED,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAChC,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBACpD,IAAI,KAAK,EAAE,CAAC;oBACV,KAAK,CAAC,sBAAsB,EAAE,CAAC;oBAC/B,MAAM,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;oBAC9B,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBAC3C,CAAC;gBACD,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;gBAC7D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,WAAW,EAAE,EAAE,YAAY,CAAC,CAAC;YAC5F,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,8DAA8D;QAC9D,iCAAiC;QACjC,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YACnC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE;gBACtC,WAAW,EAAE,CAAC;gBACd,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,UAAU,CACtB,OAAoB,EACpB,GAA6B,EAC7B,GAA6B,EAC7B,GAA6B,EAC7B,YAAoB;QAEpB,MAAM,mBAAmB,GAAc;YACrC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE;SAC1C,CAAC;QAEF,sBAAsB;QACtB,MAAM,WAAW,GAAG,iBAAiB,CACnC,IAAI,CAAC,MAAM,EACX,OAAO,CAAC,QAAQ,EAChB,IAAI,CAAC,MAAM,EACX,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,CACnB,CAAC;QAEF,uDAAuD;QACvD,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC;QAE/B,MAAM,KAAK,GAAsB;YAC/B,OAAO;YACP,mBAAmB;YACnB,UAAU;YACV,sBAAsB,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,WAAW,EAAE;SACxD,CAAC;QACF,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAE/C,qDAAqD;QACrD,UAAU,CAAC,YAAY,CAAC,KAAK,EAAE,MAAwB,EAAE,EAAE;YACzD,IAAI,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAO,CAAC,8BAA8B;YAE3D,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC5C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,mCAAmC,CAAC,CAAC;YAEvF,wCAAwC;YACxC,mBAAmB,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;YAEjE,2BAA2B;YAC3B,IAAI,CAAC;gBACH,IAAI,YAAY,GAAG,EAAE,CAAC;gBACtB,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC;gBAE/B,+BAA+B;gBAC/B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,UAAU,CAAC,IAAI,CAAC,mBAAmB,CAAC,EAAE,CAAC;oBAC/D,YAAY,IAAI,KAAK,CAAC;oBACtB,sEAAsE;oBACtE,IAAI,YAAY,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBAC7D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,wCAAwC,CAAC,CAAC;oBAC9F,CAAC;gBACH,CAAC;gBAED,IAAI,CAAC,YAAY;oBAAE,OAAO;gBAE1B,uCAAuC;gBACvC,mBAAmB,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;gBAEvE,yCAAyC;gBACzC,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC;gBAC/B,MAAM,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;gBAExD,MAAM,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;YACxE,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBAClE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,gBAAgB,CAAC,CAAC;gBACxF,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;YACjD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,0DAA0D;QAC1D,IAAI,CAAC;YACH,MAAM,UAAU,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAClE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,kBAAkB,CAAC,CAAC;YAC1F,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAED,4EAA4E;IAEpE,KAAK,CAAC,uBAAuB,CACnC,GAA6B,EAC7B,YAAuF,EACvF,OAAiE;QAEjE,IAAI,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACnE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACrD,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAC5D,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;gBACrF,MAAM,WAAW,GAAgB,KAAK,CAAC,IAAI,KAAK,UAAU;oBACxD,CAAC,CAAC,KAAK,CAAC,OAAO;oBACf,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;gBAE1F,MAAM,WAAW,GAAG,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC9F,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC;gBAE/B,UAAU,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;oBACvC,MAAM,YAAY,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;gBAC5C,CAAC,CAAC,CAAC;gBAEH,UAAU,CAAC,WAAW,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,GAAY,EAAE,EAAE;oBACzE,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;oBAClE,MAAM,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;gBACnC,CAAC,CAAC,CAAC;YACL,CAAC;YAED,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC/D,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;gBAC/E,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBAC9C,IAAI,KAAK,EAAE,CAAC;oBACV,KAAK,CAAC,sBAAsB,EAAE,CAAC;oBAC/B,MAAM,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;oBAC9B,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACrC,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YACnC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE;gBACtC,WAAW,EAAE,CAAC;gBACd,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,YAAY;QAClB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YAC1C,KAAK,CAAC,sBAAsB,EAAE,CAAC;YAC/B,KAAK,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACrC,CAAC;CACF"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Session Manager
3
+ *
4
+ * Lists active call/conference sessions and manages session metadata.
5
+ * REST API: GET /api/v1/sessions, PUT /api/v1/sessions/{linkedId}/meta
6
+ */
7
+ import type { CallSession, Logger } from '../types/index.js';
8
+ import type { HttpClient } from '../transport/http-client.js';
9
+ export declare class SessionManager {
10
+ private readonly http;
11
+ private readonly logger;
12
+ constructor(http: HttpClient, logger: Logger);
13
+ /** List all currently active call sessions */
14
+ listSessions(): Promise<CallSession[]>;
15
+ /** List active call sessions filtered by tenant ID */
16
+ listSessionsByTenant(tenantId: string): Promise<CallSession[]>;
17
+ /** Update metadata key-value pairs on a session */
18
+ updateMetadata(linkedId: string, meta: Record<string, string>): Promise<void>;
19
+ private normalizeSession;
20
+ }
21
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/session/manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAc9D,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM;IAK5C,8CAA8C;IACxC,YAAY,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAU5C,sDAAsD;IAChD,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAYpE,mDAAmD;IAC7C,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC,IAAI,CAAC;IAahB,OAAO,CAAC,gBAAgB;CAazB"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Session Manager
3
+ *
4
+ * Lists active call/conference sessions and manages session metadata.
5
+ * REST API: GET /api/v1/sessions, PUT /api/v1/sessions/{linkedId}/meta
6
+ */
7
+ export class SessionManager {
8
+ http;
9
+ logger;
10
+ constructor(http, logger) {
11
+ this.http = http;
12
+ this.logger = logger;
13
+ }
14
+ /** List all currently active call sessions */
15
+ async listSessions() {
16
+ const response = await this.http.get('/api/v1/sessions');
17
+ if (response.status !== 200) {
18
+ throw new Error(`Failed to list sessions: HTTP ${response.status}`);
19
+ }
20
+ return (response.data.sessions ?? []).map(this.normalizeSession);
21
+ }
22
+ /** List active call sessions filtered by tenant ID */
23
+ async listSessionsByTenant(tenantId) {
24
+ const response = await this.http.get(`/api/v1/sessions?tenantId=${encodeURIComponent(tenantId)}`);
25
+ if (response.status !== 200) {
26
+ throw new Error(`Failed to list sessions by tenant: HTTP ${response.status}`);
27
+ }
28
+ return (response.data.sessions ?? []).map(this.normalizeSession);
29
+ }
30
+ /** Update metadata key-value pairs on a session */
31
+ async updateMetadata(linkedId, meta) {
32
+ const response = await this.http.put(`/api/v1/sessions/${encodeURIComponent(linkedId)}/meta`, { metadata: meta });
33
+ if (response.status !== 200 && response.status !== 204) {
34
+ throw new Error(`Failed to update session metadata: HTTP ${response.status}`);
35
+ }
36
+ this.logger.debug({ linkedId, keys: Object.keys(meta) }, 'Session metadata updated');
37
+ }
38
+ normalizeSession(raw) {
39
+ return {
40
+ linkedId: raw.linkedId,
41
+ confId: raw.confId,
42
+ dir: raw.dir ?? 'both',
43
+ caller: raw.caller,
44
+ callee: raw.callee,
45
+ startedAt: raw.startedAt ? new Date(raw.startedAt) : new Date(),
46
+ streamUrl: raw.streamUrl ?? '',
47
+ tenantId: raw.tenantId,
48
+ metadata: raw.metadata,
49
+ };
50
+ }
51
+ }
52
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/session/manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiBH,MAAM,OAAO,cAAc;IACR,IAAI,CAAa;IACjB,MAAM,CAAS;IAEhC,YAAY,IAAgB,EAAE,MAAc;QAC1C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,8CAA8C;IAC9C,KAAK,CAAC,YAAY;QAChB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAA6B,kBAAkB,CAAC,CAAC;QAErF,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,iCAAiC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACtE,CAAC;QAED,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACnE,CAAC;IAED,sDAAsD;IACtD,KAAK,CAAC,oBAAoB,CAAC,QAAgB;QACzC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAClC,6BAA6B,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAC5D,CAAC;QAEF,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,2CAA2C,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAChF,CAAC;QAED,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACnE,CAAC;IAED,mDAAmD;IACnD,KAAK,CAAC,cAAc,CAClB,QAAgB,EAChB,IAA4B;QAE5B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAClC,oBAAoB,kBAAkB,CAAC,QAAQ,CAAC,OAAO,EACvD,EAAE,QAAQ,EAAE,IAAI,EAAE,CACnB,CAAC;QAEF,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvD,MAAM,IAAI,KAAK,CAAC,2CAA2C,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAChF,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,0BAA0B,CAAC,CAAC;IACvF,CAAC;IAEO,gBAAgB,CAAC,GAAe;QACtC,OAAO;YACL,QAAQ,EAAG,GAAG,CAAC,QAAQ;YACvB,MAAM,EAAK,GAAG,CAAC,MAAM;YACrB,GAAG,EAAS,GAAG,CAAC,GAA6B,IAAI,MAAM;YACvD,MAAM,EAAK,GAAG,CAAC,MAAM;YACrB,MAAM,EAAK,GAAG,CAAC,MAAM;YACrB,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE;YAC/D,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,EAAE;YAC9B,QAAQ,EAAG,GAAG,CAAC,QAAQ;YACvB,QAAQ,EAAG,GAAG,CAAC,QAAQ;SACxB,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Audio Stream
3
+ *
4
+ * Subscribes to real-time call audio from the DVGateway.
5
+ * Returns an AsyncIterable<AudioChunk> for easy integration with AI STT adapters.
6
+ *
7
+ * WebSocket endpoint: /api/v1/ws/stream?linkedid={id}&dir={both|in|out}
8
+ * Protocol: Binary frames (slin16, 16kHz, 16-bit, little-endian, 640 bytes/frame)
9
+ */
10
+ import type { AudioChunk, StreamDir, Logger } from '../types/index.js';
11
+ import type { WsPool } from '../transport/ws-pool.js';
12
+ export interface AudioStreamOptions {
13
+ dir?: StreamDir;
14
+ }
15
+ /**
16
+ * Creates an async iterable of audio chunks for a given call session.
17
+ *
18
+ * Usage:
19
+ * for await (const chunk of streamAudio(wsPool, linkedId, logger)) {
20
+ * // chunk.samples: Float32Array [-1.0, 1.0]
21
+ * // chunk.durationMs: 20
22
+ * }
23
+ *
24
+ * The iterable ends when the call is hung up or unsubscribe() is called.
25
+ */
26
+ export declare function createAudioStream(wsPool: WsPool, linkedId: string, logger: Logger, opts?: AudioStreamOptions): AsyncIterable<AudioChunk> & {
27
+ unsubscribe: () => void;
28
+ };
29
+ //# sourceMappingURL=audio-stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-stream.d.ts","sourceRoot":"","sources":["../../src/streams/audio-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAMtD,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,EAAE,SAAS,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,kBAAuB,GAC5B,aAAa,CAAC,UAAU,CAAC,GAAG;IAAE,WAAW,EAAE,MAAM,IAAI,CAAA;CAAE,CAwGzD"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Audio Stream
3
+ *
4
+ * Subscribes to real-time call audio from the DVGateway.
5
+ * Returns an AsyncIterable<AudioChunk> for easy integration with AI STT adapters.
6
+ *
7
+ * WebSocket endpoint: /api/v1/ws/stream?linkedid={id}&dir={both|in|out}
8
+ * Protocol: Binary frames (slin16, 16kHz, 16-bit, little-endian, 640 bytes/frame)
9
+ */
10
+ import { v4 as uuidv4 } from 'uuid';
11
+ import { slin16ToFloat32 } from '../audio/codec.js';
12
+ const SAMPLE_RATE = 16000;
13
+ const BYTES_PER_SAMPLE = 2;
14
+ const FRAME_BYTES = 640; // 320 samples × 2 bytes = 20ms at 16kHz
15
+ /**
16
+ * Creates an async iterable of audio chunks for a given call session.
17
+ *
18
+ * Usage:
19
+ * for await (const chunk of streamAudio(wsPool, linkedId, logger)) {
20
+ * // chunk.samples: Float32Array [-1.0, 1.0]
21
+ * // chunk.durationMs: 20
22
+ * }
23
+ *
24
+ * The iterable ends when the call is hung up or unsubscribe() is called.
25
+ */
26
+ export function createAudioStream(wsPool, linkedId, logger, opts = {}) {
27
+ const dir = opts.dir ?? 'both';
28
+ const subId = `audio-${linkedId}-${uuidv4()}`;
29
+ const queue = [];
30
+ let waitResolve = null;
31
+ let ended = false;
32
+ function push(chunk) {
33
+ queue.push(chunk);
34
+ if (waitResolve) {
35
+ const r = waitResolve;
36
+ waitResolve = null;
37
+ r();
38
+ }
39
+ }
40
+ // Subscribe to WebSocket — fire-and-forget, errors surface via 'end'
41
+ void wsPool.subscribe({
42
+ id: subId,
43
+ path: '/api/v1/ws/stream',
44
+ params: { linkedid: linkedId, dir },
45
+ onMessage: (data) => {
46
+ if (ended)
47
+ return;
48
+ const timestampMs = Date.now();
49
+ // Handle multiple frames in one message (gateway may batch)
50
+ let offset = 0;
51
+ while (offset + FRAME_BYTES <= data.byteLength) {
52
+ const frameBytes = data.subarray(offset, offset + FRAME_BYTES);
53
+ const samples = slin16ToFloat32(frameBytes);
54
+ const durationMs = (samples.length / SAMPLE_RATE) * 1000;
55
+ push({
56
+ linkedId,
57
+ dir: dir === 'both' ? 'mixed' : dir,
58
+ samples,
59
+ sampleRate: SAMPLE_RATE,
60
+ durationMs,
61
+ timestampMs: timestampMs + offset / (SAMPLE_RATE * BYTES_PER_SAMPLE / 1000),
62
+ });
63
+ offset += FRAME_BYTES;
64
+ }
65
+ // Handle partial frame (rare, but possible)
66
+ if (offset < data.byteLength) {
67
+ const partial = data.subarray(offset);
68
+ const samples = slin16ToFloat32(partial);
69
+ const durationMs = (samples.length / SAMPLE_RATE) * 1000;
70
+ push({ linkedId, dir: dir === 'both' ? 'mixed' : dir, samples, sampleRate: SAMPLE_RATE, durationMs, timestampMs });
71
+ }
72
+ },
73
+ onClose: () => {
74
+ logger.debug({ linkedId }, 'Audio stream WebSocket closed');
75
+ push('end');
76
+ },
77
+ }).catch((err) => {
78
+ logger.error({ linkedId, err }, 'Audio stream subscription failed');
79
+ push('end');
80
+ });
81
+ const iterable = {
82
+ unsubscribe: () => {
83
+ ended = true;
84
+ wsPool.unsubscribe(subId);
85
+ push('end');
86
+ },
87
+ [Symbol.asyncIterator]() {
88
+ return {
89
+ async next() {
90
+ // eslint-disable-next-line no-constant-condition
91
+ while (true) {
92
+ if (queue.length > 0) {
93
+ const entry = queue.shift();
94
+ if (entry === 'end') {
95
+ return { done: true, value: undefined };
96
+ }
97
+ return { done: false, value: entry };
98
+ }
99
+ if (ended) {
100
+ return { done: true, value: undefined };
101
+ }
102
+ // Wait for the next message
103
+ await new Promise((resolve) => {
104
+ waitResolve = resolve;
105
+ });
106
+ }
107
+ },
108
+ return() {
109
+ ended = true;
110
+ wsPool.unsubscribe(subId);
111
+ return Promise.resolve({ done: true, value: undefined });
112
+ },
113
+ };
114
+ },
115
+ };
116
+ return iterable;
117
+ }
118
+ //# sourceMappingURL=audio-stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-stream.js","sourceRoot":"","sources":["../../src/streams/audio-stream.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Call Event Stream
3
+ *
4
+ * Subscribes to real-time call lifecycle events from the DVGateway.
5
+ * Events: call:new, call:ended, conf:join, conf:leave, conf:ended
6
+ *
7
+ * WebSocket endpoint: /api/v1/ws/callinfo
8
+ * Protocol: JSON text frames
9
+ */
10
+ import type { CallEvent, Unsubscribe, Logger } from '../types/index.js';
11
+ import type { WsPool } from '../transport/ws-pool.js';
12
+ type CallEventHandler = (event: CallEvent) => void | Promise<void>;
13
+ export declare class CallEventStream {
14
+ private readonly wsPool;
15
+ private readonly logger;
16
+ private readonly handlers;
17
+ private subscriptionId;
18
+ constructor(wsPool: WsPool, logger: Logger);
19
+ /**
20
+ * Subscribe to all call events.
21
+ * Returns an unsubscribe function.
22
+ */
23
+ on(handler: CallEventHandler): Unsubscribe;
24
+ /** Subscribe to a specific event type */
25
+ onType<T extends CallEvent>(type: T['type'], handler: (event: T) => void | Promise<void>): Unsubscribe;
26
+ private startSubscription;
27
+ private stopSubscription;
28
+ private handleMessage;
29
+ private normalizeEvent;
30
+ }
31
+ export {};
32
+ //# sourceMappingURL=call-events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call-events.d.ts","sourceRoot":"","sources":["../../src/streams/call-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,KAAK,gBAAgB,GAAG,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnE,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+B;IACxD,OAAO,CAAC,cAAc,CAAuB;gBAEjC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAK1C;;;OAGG;IACH,EAAE,CAAC,OAAO,EAAE,gBAAgB,GAAG,WAAW;IAiB1C,yCAAyC;IACzC,MAAM,CAAC,CAAC,SAAS,SAAS,EACxB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,EACf,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAC1C,WAAW;YAQA,iBAAiB;IAgB/B,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,aAAa;IAoBrB,OAAO,CAAC,cAAc;CA6DvB"}