@telnyx/react-voice-commons-sdk 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +469 -483
  3. package/ios/CallKitBridge.swift +2 -7
  4. package/lib/callkit/callkit-coordinator.d.ts +110 -117
  5. package/lib/callkit/callkit-coordinator.js +664 -727
  6. package/lib/callkit/callkit.d.ts +41 -41
  7. package/lib/callkit/callkit.js +252 -242
  8. package/lib/callkit/index.js +15 -47
  9. package/lib/callkit/use-callkit.d.ts +19 -19
  10. package/lib/callkit/use-callkit.js +270 -310
  11. package/lib/context/TelnyxVoiceContext.d.ts +9 -9
  12. package/lib/context/TelnyxVoiceContext.js +10 -13
  13. package/lib/hooks/use-callkit-coordinator.d.ts +9 -17
  14. package/lib/hooks/use-callkit-coordinator.js +45 -50
  15. package/lib/hooks/useAppReadyNotifier.js +13 -15
  16. package/lib/hooks/useAppStateHandler.d.ts +6 -11
  17. package/lib/hooks/useAppStateHandler.js +95 -110
  18. package/lib/hooks/useNetworkStateHandler.d.ts +0 -0
  19. package/lib/hooks/useNetworkStateHandler.js +0 -0
  20. package/lib/index.d.ts +3 -21
  21. package/lib/index.js +50 -201
  22. package/lib/internal/CallKitHandler.d.ts +6 -6
  23. package/lib/internal/CallKitHandler.js +96 -104
  24. package/lib/internal/callkit-manager.d.ts +57 -57
  25. package/lib/internal/callkit-manager.js +299 -316
  26. package/lib/internal/calls/call-state-controller.d.ts +73 -86
  27. package/lib/internal/calls/call-state-controller.js +263 -307
  28. package/lib/internal/session/session-manager.d.ts +71 -75
  29. package/lib/internal/session/session-manager.js +360 -424
  30. package/lib/internal/user-defaults-helpers.js +49 -39
  31. package/lib/internal/voice-pn-bridge.d.ts +114 -12
  32. package/lib/internal/voice-pn-bridge.js +212 -5
  33. package/lib/models/call-state.d.ts +46 -44
  34. package/lib/models/call-state.js +70 -68
  35. package/lib/models/call.d.ts +161 -133
  36. package/lib/models/call.js +454 -382
  37. package/lib/models/config.d.ts +11 -18
  38. package/lib/models/config.js +37 -35
  39. package/lib/models/connection-state.d.ts +10 -10
  40. package/lib/models/connection-state.js +16 -16
  41. package/lib/telnyx-voice-app.d.ts +28 -28
  42. package/lib/telnyx-voice-app.js +513 -480
  43. package/lib/telnyx-voip-client.d.ts +167 -167
  44. package/lib/telnyx-voip-client.js +385 -390
  45. package/package.json +115 -104
  46. package/src/callkit/callkit-coordinator.ts +830 -846
  47. package/src/hooks/useNetworkStateHandler.ts +0 -0
  48. package/src/internal/calls/call-state-controller.ts +407 -384
  49. package/src/internal/session/session-manager.ts +483 -467
  50. package/src/internal/voice-pn-bridge.ts +266 -18
  51. package/src/models/call-state.ts +105 -98
  52. package/src/models/call.ts +502 -388
  53. package/src/telnyx-voice-app.tsx +788 -690
  54. package/src/telnyx-voip-client.ts +551 -539
  55. package/src/types/telnyx-sdk.d.ts +93 -79
@@ -1,11 +1,11 @@
1
- 'use strict';
2
- Object.defineProperty(exports, '__esModule', { value: true });
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CallStateController = void 0;
4
- const rxjs_1 = require('rxjs');
5
- const operators_1 = require('rxjs/operators');
6
- const call_1 = require('../../models/call');
7
- const call_state_1 = require('../../models/call-state');
8
- const callkit_coordinator_1 = require('../../callkit/callkit-coordinator');
4
+ const rxjs_1 = require("rxjs");
5
+ const operators_1 = require("rxjs/operators");
6
+ const call_1 = require("../../models/call");
7
+ const call_state_1 = require("../../models/call-state");
8
+ const callkit_coordinator_1 = require("../../callkit/callkit-coordinator");
9
9
  /**
10
10
  * Central state machine for call management.
11
11
  *
@@ -13,320 +13,276 @@ const callkit_coordinator_1 = require('../../callkit/callkit-coordinator');
13
13
  * and provides reactive streams for call-related state changes.
14
14
  */
15
15
  class CallStateController {
16
- constructor(_sessionManager) {
17
- this._sessionManager = _sessionManager;
18
- this._calls = new rxjs_1.BehaviorSubject([]);
19
- this._callMap = new Map();
20
- this._disposed = false;
21
- // Don't set up client listeners here - client doesn't exist yet
22
- // Will be called when client is available
23
- }
24
- /**
25
- * Observable stream of all current calls
26
- */
27
- get calls$() {
28
- return this._calls.asObservable().pipe((0, operators_1.distinctUntilChanged)());
29
- }
30
- /**
31
- * Observable stream of the currently active call
32
- */
33
- get activeCall$() {
34
- return this.calls$.pipe(
35
- (0, operators_1.map)((calls) => {
36
- // Find the first call that is not terminated (includes RINGING, CONNECTING, ACTIVE, HELD)
37
- return (
38
- calls.find(
39
- (call) =>
40
- call.currentState === call_state_1.TelnyxCallState.RINGING ||
41
- call.currentState === call_state_1.TelnyxCallState.CONNECTING ||
42
- call.currentState === call_state_1.TelnyxCallState.ACTIVE ||
43
- call.currentState === call_state_1.TelnyxCallState.HELD
44
- ) || null
45
- );
46
- }),
47
- (0, operators_1.distinctUntilChanged)()
48
- );
49
- }
50
- /**
51
- * Current list of calls (synchronous access)
52
- */
53
- get currentCalls() {
54
- return this._calls.value;
55
- }
56
- /**
57
- * Current active call (synchronous access)
58
- */
59
- get currentActiveCall() {
60
- const calls = this.currentCalls;
61
- return (
62
- calls.find(
63
- (call) =>
64
- call.currentState === call_state_1.TelnyxCallState.RINGING ||
65
- call.currentState === call_state_1.TelnyxCallState.CONNECTING ||
66
- call.currentState === call_state_1.TelnyxCallState.ACTIVE ||
67
- call.currentState === call_state_1.TelnyxCallState.HELD
68
- ) || null
69
- );
70
- }
71
- /**
72
- * Set a call to connecting state (used for push notification calls when answered via CallKit)
73
- * @param callId The ID of the call to set to connecting state
74
- */
75
- setCallConnecting(callId) {
76
- const call = this._callMap.get(callId);
77
- if (call) {
78
- console.log('CallStateController: Setting call to connecting state:', callId);
79
- call.setConnecting();
80
- } else {
81
- console.warn('CallStateController: Could not find call to set connecting:', callId);
16
+ constructor(_sessionManager) {
17
+ this._sessionManager = _sessionManager;
18
+ this._calls = new rxjs_1.BehaviorSubject([]);
19
+ this._callMap = new Map();
20
+ this._disposed = false;
21
+ console.log('🔧 CallStateController: Constructor called - instance created');
22
+ // Don't set up client listeners here - client doesn't exist yet
23
+ // Will be called when client is available
82
24
  }
83
- }
84
- /**
85
- * Find a call by its underlying Telnyx call ID
86
- * @param telnyxCall The Telnyx call object to find
87
- */
88
- findCallByTelnyxCall(telnyxCall) {
89
- for (const call of this._callMap.values()) {
90
- if (call.telnyxCall === telnyxCall || call.telnyxCall.callId === telnyxCall.callId) {
91
- return call;
92
- }
25
+ /**
26
+ * Observable stream of all current calls
27
+ */
28
+ get calls$() {
29
+ return this._calls.asObservable().pipe((0, operators_1.distinctUntilChanged)());
93
30
  }
94
- return null;
95
- }
96
- /**
97
- * Initialize client listeners when the Telnyx client becomes available
98
- * This should be called by the session manager after client creation
99
- */
100
- initializeClientListeners() {
101
- console.log('🔧 CallStateController: initializeClientListeners called');
102
- this._setupClientListeners();
103
- // CallKit integration now handled by CallKitCoordinator
104
- console.log('🔧 CallStateController: Using CallKitCoordinator for CallKit integration');
105
- }
106
- /**
107
- * Initiate a new outgoing call
108
- */
109
- async newCall(destination, callerName, callerNumber, debug = false) {
110
- if (this._disposed) {
111
- throw new Error('CallStateController has been disposed');
31
+ /**
32
+ * Observable stream of the currently active call
33
+ */
34
+ get activeCall$() {
35
+ return this.calls$.pipe((0, operators_1.map)((calls) => {
36
+ // Find the first call that is not terminated (includes RINGING, CONNECTING, ACTIVE, HELD)
37
+ return (calls.find((call) => call.currentState === call_state_1.TelnyxCallState.RINGING ||
38
+ call.currentState === call_state_1.TelnyxCallState.CONNECTING ||
39
+ call.currentState === call_state_1.TelnyxCallState.ACTIVE ||
40
+ call.currentState === call_state_1.TelnyxCallState.HELD) || null);
41
+ }), (0, operators_1.distinctUntilChanged)());
112
42
  }
113
- if (!this._sessionManager.telnyxClient) {
114
- throw new Error('Telnyx client not available');
43
+ /**
44
+ * Current list of calls (synchronous access)
45
+ */
46
+ get currentCalls() {
47
+ return this._calls.value;
115
48
  }
116
- try {
117
- // Create the call using the Telnyx SDK
118
- const callOptions = {
119
- destinationNumber: destination,
120
- callerIdName: callerName,
121
- callerIdNumber: callerNumber,
122
- };
123
- const telnyxCall = await this._sessionManager.telnyxClient.newCall(callOptions);
124
- // Create our wrapper Call object
125
- const call = new call_1.Call(
126
- telnyxCall,
127
- telnyxCall.callId || this._generateCallId(),
128
- destination,
129
- false // outgoing call
130
- );
131
- // Add to our call tracking
132
- this._addCall(call);
133
- return call;
134
- } catch (error) {
135
- console.error('Failed to create new call:', error);
136
- throw error;
49
+ /**
50
+ * Current active call (synchronous access)
51
+ */
52
+ get currentActiveCall() {
53
+ const calls = this.currentCalls;
54
+ return (calls.find((call) => call.currentState === call_state_1.TelnyxCallState.RINGING ||
55
+ call.currentState === call_state_1.TelnyxCallState.CONNECTING ||
56
+ call.currentState === call_state_1.TelnyxCallState.ACTIVE ||
57
+ call.currentState === call_state_1.TelnyxCallState.HELD) || null);
137
58
  }
138
- }
139
- /**
140
- * Set callbacks for waiting for invite logic (used for push notifications)
141
- */
142
- setWaitingForInviteCallbacks(callbacks) {
143
- this._isWaitingForInvite = callbacks.isWaitingForInvite;
144
- this._onInviteAutoAccepted = callbacks.onInviteAutoAccepted;
145
- }
146
- /**
147
- * Dispose of the controller and clean up resources
148
- */
149
- dispose() {
150
- if (this._disposed) {
151
- return;
59
+ /**
60
+ * Set a call to connecting state (used for push notification calls when answered via CallKit)
61
+ * @param callId The ID of the call to set to connecting state
62
+ */
63
+ setCallConnecting(callId) {
64
+ const call = this._callMap.get(callId);
65
+ if (call) {
66
+ console.log('CallStateController: Setting call to connecting state:', callId);
67
+ call.setConnecting();
68
+ }
69
+ else {
70
+ console.warn('CallStateController: Could not find call to set connecting:', callId);
71
+ }
152
72
  }
153
- this._disposed = true;
154
- // Dispose of all calls
155
- this.currentCalls.forEach((call) => call.dispose());
156
- this._callMap.clear();
157
- // CallKit cleanup is now handled by CallKitCoordinator automatically
158
- this._calls.complete();
159
- }
160
- /**
161
- * Set up event listeners for the Telnyx client
162
- */
163
- _setupClientListeners() {
164
- console.log('🔧 CallStateController: Setting up client listeners...');
165
- if (!this._sessionManager.telnyxClient) {
166
- console.log('🔧 CallStateController: No telnyxClient available yet, skipping listener setup');
167
- return;
73
+ /**
74
+ * Find a call by its underlying Telnyx call ID
75
+ * @param telnyxCall The Telnyx call object to find
76
+ */
77
+ findCallByTelnyxCall(telnyxCall) {
78
+ for (const call of this._callMap.values()) {
79
+ if (call.telnyxCall === telnyxCall || call.telnyxCall.callId === telnyxCall.callId) {
80
+ return call;
81
+ }
82
+ }
83
+ return null;
168
84
  }
169
- console.log('🔧 CallStateController: TelnyxClient found, setting up incoming call listener');
170
- // Listen for incoming calls
171
- this._sessionManager.telnyxClient.on('telnyx.call.incoming', (telnyxCall, msg) => {
172
- console.log('📞 CallStateController: Incoming call received:', telnyxCall.callId);
173
- this._handleIncomingCall(telnyxCall, msg);
174
- });
175
- // Listen for other call events if needed
176
- // this._sessionManager.telnyxClient.on('telnyx.call.stateChange', this._handleCallStateChange.bind(this));
177
- console.log('🔧 CallStateController: Client listeners set up successfully');
178
- }
179
- /**
180
- * Handle incoming call
181
- */
182
- _handleIncomingCall(telnyxCall, inviteMsg) {
183
- const callId = telnyxCall.callId || this._generateCallId();
184
- console.log('📞 CallStateController: Handling incoming call:', callId);
185
- console.log('📞 CallStateController: TelnyxCall object:', telnyxCall);
186
- console.log('📞 CallStateController: Invite message:', inviteMsg);
187
- // Check if we already have this call
188
- if (this._callMap.has(callId)) {
189
- console.log('Call already exists:', callId);
190
- return;
85
+ /**
86
+ * Initialize client listeners when the Telnyx client becomes available
87
+ * This should be called by the session manager after client creation
88
+ */
89
+ initializeClientListeners() {
90
+ console.log('🔧 CallStateController: initializeClientListeners called');
91
+ console.log('🔧 CallStateController: Current client exists:', !!this._sessionManager.telnyxClient);
92
+ this._setupClientListeners();
93
+ // CallKit integration now handled by CallKitCoordinator
94
+ console.log('🔧 CallStateController: Using CallKitCoordinator for CallKit integration');
191
95
  }
192
- // Get caller information from the invite message (preferred) or fallback to TelnyxCall
193
- let callerNumber = 'Unknown';
194
- let callerName = 'Unknown';
195
- if (inviteMsg && inviteMsg.params) {
196
- callerNumber = inviteMsg.params.caller_id_number || 'Unknown';
197
- callerName = inviteMsg.params.caller_id_name || callerNumber;
198
- console.log(
199
- '📞 CallStateController: Extracted caller info from invite - Number:',
200
- callerNumber,
201
- 'Name:',
202
- callerName
203
- );
204
- } else {
205
- // Fallback to TelnyxCall properties
206
- callerNumber = telnyxCall.remoteCallerIdNumber || 'Unknown';
207
- callerName = telnyxCall.remoteCallerIdName || callerNumber;
208
- console.log(
209
- '📞 CallStateController: Extracted caller info from TelnyxCall - Number:',
210
- callerNumber,
211
- 'Name:',
212
- callerName
213
- );
96
+ /**
97
+ * Initiate a new outgoing call
98
+ */
99
+ async newCall(destination, callerName, callerNumber, customHeaders) {
100
+ if (this._disposed) {
101
+ throw new Error('CallStateController has been disposed');
102
+ }
103
+ if (!this._sessionManager.telnyxClient) {
104
+ throw new Error('Telnyx client not available');
105
+ }
106
+ try {
107
+ // Create the call using the Telnyx SDK
108
+ const callOptions = {
109
+ destinationNumber: destination,
110
+ callerIdName: callerName,
111
+ callerIdNumber: callerNumber,
112
+ customHeaders,
113
+ };
114
+ const telnyxCall = await this._sessionManager.telnyxClient.newCall(callOptions);
115
+ // Create our wrapper Call object
116
+ const call = new call_1.Call(telnyxCall, telnyxCall.callId || this._generateCallId(), destination, false, // outgoing call
117
+ false, // not reattached
118
+ callerName || destination, // use destination as fallback for caller name
119
+ callerNumber // original caller number
120
+ );
121
+ // Add to our call tracking
122
+ this._addCall(call);
123
+ return call;
124
+ }
125
+ catch (error) {
126
+ console.error('Failed to create new call:', error);
127
+ throw error;
128
+ }
214
129
  }
215
- // Create our wrapper Call object
216
- const call = new call_1.Call(
217
- telnyxCall,
218
- callId,
219
- callerNumber, // Use caller number as destination for incoming calls
220
- true // incoming call
221
- );
222
- // Check if we're waiting for an invite (push notification scenario)
223
- if (this._isWaitingForInvite && this._isWaitingForInvite()) {
224
- console.log('Auto-accepting call from push notification');
225
- call.answer().catch((error) => {
226
- console.error('Failed to auto-accept call:', error);
227
- });
228
- if (this._onInviteAutoAccepted) {
229
- this._onInviteAutoAccepted();
230
- }
130
+ /**
131
+ * Set callbacks for waiting for invite logic (used for push notifications)
132
+ */
133
+ setWaitingForInviteCallbacks(callbacks) {
134
+ this._isWaitingForInvite = callbacks.isWaitingForInvite;
135
+ this._onInviteAutoAccepted = callbacks.onInviteAutoAccepted;
231
136
  }
232
- // Add to our call tracking - CallKit integration happens in _addCall
233
- this._addCall(call);
234
- }
235
- /**
236
- * Handle call state changes from the Telnyx client
237
- */
238
- _handleCallStateChange(event) {
239
- const callId = event.callId || event.id;
240
- const call = this._callMap.get(callId);
241
- if (call) {
242
- // The Call object will handle its own state updates through its listeners
243
- console.log(`Call ${callId} state changed to ${event.state}`);
244
- } else {
245
- console.warn(`Received state change for unknown call: ${callId}`);
137
+ /**
138
+ * Dispose of the controller and clean up resources
139
+ */
140
+ dispose() {
141
+ if (this._disposed) {
142
+ return;
143
+ }
144
+ this._disposed = true;
145
+ // Dispose of all calls
146
+ this.currentCalls.forEach((call) => call.dispose());
147
+ this._callMap.clear();
148
+ // CallKit cleanup is now handled by CallKitCoordinator automatically
149
+ this._calls.complete();
246
150
  }
247
- }
248
- /**
249
- * Handle call updates from notifications
250
- */
251
- _handleCallUpdate(callData) {
252
- const callId = callData.id;
253
- const call = this._callMap.get(callId);
254
- if (call) {
255
- // Update call state based on the notification
256
- console.log(`Call ${callId} updated:`, callData);
257
- } else {
258
- console.warn(`Received update for unknown call: ${callId}`);
151
+ /**
152
+ * Set up event listeners for the Telnyx client
153
+ */
154
+ _setupClientListeners() {
155
+ console.log('🔧 CallStateController: Setting up client listeners...');
156
+ if (!this._sessionManager.telnyxClient) {
157
+ console.log('🔧 CallStateController: No telnyxClient available yet, skipping listener setup');
158
+ return;
159
+ }
160
+ console.log('🔧 CallStateController: TelnyxClient found, setting up incoming call listener');
161
+ console.log('🔧 CallStateController: Client instance:', this._sessionManager.telnyxClient.constructor.name);
162
+ // Listen for incoming calls
163
+ this._sessionManager.telnyxClient.on('telnyx.call.incoming', (telnyxCall, msg) => {
164
+ console.log('📞 CallStateController: Incoming call received:', telnyxCall.callId);
165
+ this._handleIncomingCall(telnyxCall, msg, false);
166
+ });
167
+ // Listen for reattached calls (after network reconnection)
168
+ this._sessionManager.telnyxClient.on('telnyx.call.reattached', (telnyxCall, msg) => {
169
+ console.log('📞 CallStateController: Reattached call received:', telnyxCall.callId);
170
+ this._handleIncomingCall(telnyxCall, msg, true);
171
+ });
172
+ // Verify listeners are set up
173
+ const incomingListeners = this._sessionManager.telnyxClient.listenerCount('telnyx.call.incoming');
174
+ const reattachedListeners = this._sessionManager.telnyxClient.listenerCount('telnyx.call.reattached');
175
+ console.log('🔧 CallStateController: Listeners registered - incoming:', incomingListeners, 'reattached:', reattachedListeners);
176
+ // Listen for other call events if needed
177
+ // this._sessionManager.telnyxClient.on('telnyx.call.stateChange', this._handleCallStateChange.bind(this));
178
+ console.log('🔧 CallStateController: Client listeners set up successfully');
259
179
  }
260
- }
261
- /**
262
- * Add a call to our tracking
263
- */
264
- _addCall(call) {
265
- this._callMap.set(call.callId, call);
266
- const currentCalls = this.currentCalls;
267
- currentCalls.push(call);
268
- this._calls.next([...currentCalls]);
269
- // Integrate with CallKit using CallKitCoordinator
270
- if (callkit_coordinator_1.callKitCoordinator.isAvailable()) {
271
- // Get the underlying TelnyxCall for CallKitCoordinator
272
- const telnyxCall = call.telnyxCall;
273
- // Check if this call already has CallKit integration (e.g., from push notification)
274
- const existingCallKitUUID =
275
- callkit_coordinator_1.callKitCoordinator.getCallKitUUID(telnyxCall);
276
- if (existingCallKitUUID) {
277
- console.log(
278
- 'CallStateController: Call already has CallKit integration, skipping duplicate report:',
279
- existingCallKitUUID
280
- );
281
- } else if (call.isIncoming) {
282
- // Handle incoming call with CallKit (only if not already integrated)
283
- console.log('CallStateController: Reporting incoming call to CallKitCoordinator');
284
- callkit_coordinator_1.callKitCoordinator.reportIncomingCall(
285
- telnyxCall,
286
- call.destination,
287
- call.destination
288
- );
289
- } else {
290
- // Handle outgoing call with CallKit
291
- console.log('CallStateController: Starting outgoing call with CallKitCoordinator');
292
- callkit_coordinator_1.callKitCoordinator.startOutgoingCall(
293
- telnyxCall,
294
- call.destination,
295
- call.destination
180
+ /**
181
+ * Handle incoming call or reattached call
182
+ */
183
+ _handleIncomingCall(telnyxCall, inviteMsg, isReattached = false) {
184
+ const callId = telnyxCall.callId || this._generateCallId();
185
+ console.log('📞 CallStateController: Handling incoming call:', callId, 'isReattached:', isReattached);
186
+ console.log('📞 CallStateController: TelnyxCall object:', telnyxCall);
187
+ console.log('📞 CallStateController: Invite message:', inviteMsg);
188
+ // For reattached calls, remove existing call and create new one
189
+ if (isReattached && this._callMap.has(callId)) {
190
+ console.log('📞 CallStateController: Removing existing call for reattachment');
191
+ const existingCall = this._callMap.get(callId);
192
+ if (existingCall) {
193
+ console.log('📞 CallStateController: Existing call state before removal:', existingCall.currentState);
194
+ this._removeCall(callId);
195
+ }
196
+ }
197
+ // Check if we already have this call (for non-reattached calls)
198
+ if (this._callMap.has(callId) && !isReattached) {
199
+ console.log('Call already exists:', callId);
200
+ return;
201
+ }
202
+ // Get caller information from the invite message (preferred) or fallback to TelnyxCall
203
+ let callerNumber = '';
204
+ let callerName = '';
205
+ if (inviteMsg && inviteMsg.params) {
206
+ callerNumber = inviteMsg.params.caller_id_number || '';
207
+ callerName = inviteMsg.params.caller_id_name || '';
208
+ console.log('📞 CallStateController: Extracted caller info from invite - Number:', callerNumber, 'Name:', callerName);
209
+ }
210
+ else {
211
+ // Fallback to TelnyxCall properties
212
+ callerNumber = telnyxCall.remoteCallerIdNumber || '';
213
+ callerName = telnyxCall.remoteCallerIdName || '';
214
+ console.log('📞 CallStateController: Extracted caller info from TelnyxCall - Number:', callerNumber, 'Name:', callerName);
215
+ }
216
+ // Use smart fallbacks - prefer caller number over "Unknown"
217
+ const finalCallerNumber = callerNumber || 'Unknown Number';
218
+ const finalCallerName = callerName || callerNumber || 'Unknown Caller';
219
+ // Create our wrapper Call object
220
+ const call = new call_1.Call(telnyxCall, callId, finalCallerNumber, // Use caller number as destination for incoming calls
221
+ true, // incoming call
222
+ isReattached, // pass the reattached flag
223
+ finalCallerName, // use caller name or fallback to number
224
+ finalCallerNumber // use caller number
296
225
  );
297
- }
226
+ // Add to our call tracking - CallKit integration happens in _addCall
227
+ this._addCall(call);
228
+ }
229
+ /**
230
+ * Add a call to our tracking
231
+ */
232
+ _addCall(call) {
233
+ this._callMap.set(call.callId, call);
234
+ const currentCalls = this.currentCalls;
235
+ currentCalls.push(call);
236
+ this._calls.next([...currentCalls]);
237
+ // Integrate with CallKit using CallKitCoordinator
238
+ if (callkit_coordinator_1.callKitCoordinator.isAvailable()) {
239
+ // Get the underlying TelnyxCall for CallKitCoordinator
240
+ const telnyxCall = call.telnyxCall;
241
+ // Check if this call already has CallKit integration (e.g., from push notification)
242
+ const existingCallKitUUID = callkit_coordinator_1.callKitCoordinator.getCallKitUUID(telnyxCall);
243
+ if (existingCallKitUUID) {
244
+ console.log('CallStateController: Call already has CallKit integration, skipping duplicate report:', existingCallKitUUID);
245
+ }
246
+ else if (call.isIncoming) {
247
+ // Handle incoming call with CallKit (only if not already integrated)
248
+ console.log('CallStateController: Reporting incoming call to CallKitCoordinator');
249
+ callkit_coordinator_1.callKitCoordinator.reportIncomingCall(telnyxCall, call.destination, call.destination);
250
+ }
251
+ else {
252
+ // Handle outgoing call with CallKit
253
+ console.log('CallStateController: Starting outgoing call with CallKitCoordinator');
254
+ callkit_coordinator_1.callKitCoordinator.startOutgoingCall(telnyxCall, call.destination, call.destination);
255
+ }
256
+ }
257
+ // Listen for call state changes - CallKitCoordinator handles this automatically
258
+ call.callState$.subscribe((state) => {
259
+ // CallKitCoordinator automatically updates CallKit via setupWebRTCCallListeners
260
+ console.log('CallStateController: Call state changed to:', state);
261
+ // Clean up when call ends
262
+ if (state === call_state_1.TelnyxCallState.ENDED || state === call_state_1.TelnyxCallState.FAILED) {
263
+ this._removeCall(call.callId);
264
+ }
265
+ });
266
+ }
267
+ /**
268
+ * Remove a call from our tracking
269
+ */
270
+ _removeCall(callId) {
271
+ const call = this._callMap.get(callId);
272
+ if (call) {
273
+ console.log('CallStateController: Removing call:', callId);
274
+ // CallKit cleanup is handled automatically by CallKitCoordinator
275
+ call.dispose();
276
+ this._callMap.delete(callId);
277
+ const currentCalls = this.currentCalls.filter((c) => c.callId !== callId);
278
+ this._calls.next(currentCalls);
279
+ }
298
280
  }
299
- // Listen for call state changes - CallKitCoordinator handles this automatically
300
- call.callState$.subscribe((state) => {
301
- // CallKitCoordinator automatically updates CallKit via setupWebRTCCallListeners
302
- console.log('CallStateController: Call state changed to:', state);
303
- // Clean up when call ends
304
- if (
305
- state === call_state_1.TelnyxCallState.ENDED ||
306
- state === call_state_1.TelnyxCallState.FAILED
307
- ) {
308
- this._removeCall(call.callId);
309
- }
310
- });
311
- }
312
- /**
313
- * Remove a call from our tracking
314
- */
315
- _removeCall(callId) {
316
- const call = this._callMap.get(callId);
317
- if (call) {
318
- // CallKit cleanup is handled automatically by CallKitCoordinator
319
- call.dispose();
320
- this._callMap.delete(callId);
321
- const currentCalls = this.currentCalls.filter((c) => c.callId !== callId);
322
- this._calls.next(currentCalls);
281
+ /**
282
+ * Generate a unique call ID
283
+ */
284
+ _generateCallId() {
285
+ return `call_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
323
286
  }
324
- }
325
- /**
326
- * Generate a unique call ID
327
- */
328
- _generateCallId() {
329
- return `call_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
330
- }
331
287
  }
332
288
  exports.CallStateController = CallStateController;