@telnyx/react-voice-commons-sdk 0.1.2 → 0.1.3
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/CHANGELOG.md +42 -0
- package/TelnyxVoiceCommons.podspec +31 -31
- package/ios/CallKitBridge.m +43 -43
- package/ios/CallKitBridge.swift +874 -879
- package/ios/VoicePnBridge.m +30 -30
- package/ios/VoicePnBridge.swift +86 -86
- package/lib/callkit/callkit-coordinator.d.ts +110 -117
- package/lib/callkit/callkit-coordinator.js +664 -727
- package/lib/callkit/callkit.d.ts +41 -41
- package/lib/callkit/callkit.js +252 -242
- package/lib/callkit/index.js +15 -47
- package/lib/callkit/use-callkit.d.ts +19 -19
- package/lib/callkit/use-callkit.js +270 -310
- package/lib/context/TelnyxVoiceContext.d.ts +9 -9
- package/lib/context/TelnyxVoiceContext.js +10 -13
- package/lib/hooks/use-callkit-coordinator.d.ts +9 -17
- package/lib/hooks/use-callkit-coordinator.js +45 -50
- package/lib/hooks/useAppReadyNotifier.js +13 -15
- package/lib/hooks/useAppStateHandler.d.ts +6 -11
- package/lib/hooks/useAppStateHandler.js +95 -110
- package/lib/hooks/useNetworkStateHandler.d.ts +0 -0
- package/lib/hooks/useNetworkStateHandler.js +0 -0
- package/lib/index.d.ts +3 -21
- package/lib/index.js +50 -201
- package/lib/internal/CallKitHandler.d.ts +6 -6
- package/lib/internal/CallKitHandler.js +96 -104
- package/lib/internal/callkit-manager.d.ts +57 -57
- package/lib/internal/callkit-manager.js +299 -316
- package/lib/internal/calls/call-state-controller.d.ts +73 -86
- package/lib/internal/calls/call-state-controller.js +263 -307
- package/lib/internal/session/session-manager.d.ts +71 -75
- package/lib/internal/session/session-manager.js +360 -424
- package/lib/internal/user-defaults-helpers.js +49 -39
- package/lib/internal/voice-pn-bridge.d.ts +114 -12
- package/lib/internal/voice-pn-bridge.js +212 -5
- package/lib/models/call-state.d.ts +46 -44
- package/lib/models/call-state.js +70 -68
- package/lib/models/call.d.ts +161 -133
- package/lib/models/call.js +454 -382
- package/lib/models/config.d.ts +11 -18
- package/lib/models/config.js +37 -35
- package/lib/models/connection-state.d.ts +10 -10
- package/lib/models/connection-state.js +16 -16
- package/lib/telnyx-voice-app.d.ts +28 -28
- package/lib/telnyx-voice-app.js +463 -481
- package/lib/telnyx-voip-client.d.ts +167 -167
- package/lib/telnyx-voip-client.js +385 -390
- package/package.json +11 -4
- package/src/callkit/callkit-coordinator.ts +18 -34
- package/src/hooks/useNetworkStateHandler.ts +0 -0
- package/src/internal/calls/call-state-controller.ts +81 -58
- package/src/internal/session/session-manager.ts +42 -26
- package/src/internal/voice-pn-bridge.ts +250 -2
- package/src/models/call-state.ts +8 -1
- package/src/models/call.ts +119 -5
- package/src/telnyx-voice-app.tsx +87 -40
- package/src/telnyx-voip-client.ts +15 -3
- package/src/types/telnyx-sdk.d.ts +16 -2
|
@@ -1,319 +1,279 @@
|
|
|
1
|
-
|
|
2
|
-
var __createBinding =
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
var
|
|
23
|
-
|
|
24
|
-
(Object.create
|
|
25
|
-
? function (o, v) {
|
|
26
|
-
Object.defineProperty(o, 'default', { enumerable: true, value: v });
|
|
27
|
-
}
|
|
28
|
-
: function (o, v) {
|
|
29
|
-
o['default'] = v;
|
|
30
|
-
});
|
|
31
|
-
var __importStar =
|
|
32
|
-
(this && this.__importStar) ||
|
|
33
|
-
(function () {
|
|
34
|
-
var ownKeys = function (o) {
|
|
35
|
-
ownKeys =
|
|
36
|
-
Object.getOwnPropertyNames ||
|
|
37
|
-
function (o) {
|
|
38
|
-
var ar = [];
|
|
39
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
40
|
-
return ar;
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
41
24
|
};
|
|
42
|
-
|
|
25
|
+
return ownKeys(o);
|
|
43
26
|
};
|
|
44
27
|
return function (mod) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
__setModuleDefault(result, mod);
|
|
51
|
-
return result;
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
52
33
|
};
|
|
53
|
-
|
|
54
|
-
Object.defineProperty(exports,
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55
36
|
exports.useCallKit = useCallKit;
|
|
56
|
-
const react_1 = require(
|
|
57
|
-
const callkit_1 = __importStar(require(
|
|
37
|
+
const react_1 = require("react");
|
|
38
|
+
const callkit_1 = __importStar(require("./callkit"));
|
|
58
39
|
function useCallKit(options = {}) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
// Load existing active calls only once
|
|
88
|
-
const loadActiveCalls = async () => {
|
|
89
|
-
const calls = await callkit_1.default.getActiveCalls();
|
|
90
|
-
setActiveCalls(
|
|
91
|
-
calls.map((call) => ({
|
|
92
|
-
uuid: call.uuid,
|
|
93
|
-
handle: call.handle || call.caller || 'Unknown',
|
|
94
|
-
displayName: call.caller || call.displayName || 'Unknown Caller',
|
|
95
|
-
isActive: true,
|
|
96
|
-
direction: call.direction || 'incoming',
|
|
97
|
-
}))
|
|
98
|
-
);
|
|
99
|
-
};
|
|
100
|
-
loadActiveCalls();
|
|
101
|
-
// Set up event listeners using stable refs
|
|
102
|
-
const unsubscribeAnswer = callkit_1.default.onAnswerCall((event) => {
|
|
103
|
-
console.log('useCallKit: Call answered via CallKit', event);
|
|
104
|
-
onAnswerCallRef.current?.(event.callUUID);
|
|
105
|
-
});
|
|
106
|
-
const unsubscribeEnd = callkit_1.default.onEndCall((event) => {
|
|
107
|
-
console.log('useCallKit: Call ended via CallKit', event);
|
|
108
|
-
setActiveCalls((prev) => prev.filter((call) => call.uuid !== event.callUUID));
|
|
109
|
-
onEndCallRef.current?.(event.callUUID);
|
|
110
|
-
});
|
|
111
|
-
const unsubscribeStart = callkit_1.default.onStartCall((event) => {
|
|
112
|
-
console.log('useCallKit: Call started via CallKit', event);
|
|
113
|
-
onStartCallRef.current?.(event.callUUID);
|
|
114
|
-
});
|
|
115
|
-
return () => {
|
|
116
|
-
unsubscribeAnswer();
|
|
117
|
-
unsubscribeEnd();
|
|
118
|
-
unsubscribeStart();
|
|
119
|
-
};
|
|
120
|
-
}, []); // Empty dependency array - only run once
|
|
121
|
-
// Start an outgoing call
|
|
122
|
-
const startOutgoingCall = (0, react_1.useCallback)(async (call, handle, displayName) => {
|
|
123
|
-
if (!callkit_1.default.isAvailable()) {
|
|
124
|
-
console.warn('CallKit: Not available, cannot start outgoing call');
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
const callUUID = callkit_1.default.generateCallUUID();
|
|
128
|
-
const callHandle = handle || call.destinationNumber || 'Unknown';
|
|
129
|
-
const callDisplayName = displayName || callHandle;
|
|
130
|
-
console.log('useCallKit: Starting outgoing call', {
|
|
131
|
-
callUUID,
|
|
132
|
-
callHandle,
|
|
133
|
-
callDisplayName,
|
|
134
|
-
telnyxCallId: call.callId,
|
|
135
|
-
});
|
|
136
|
-
const success = await callkit_1.default.startOutgoingCall(
|
|
137
|
-
callUUID,
|
|
138
|
-
callHandle,
|
|
139
|
-
callDisplayName
|
|
140
|
-
);
|
|
141
|
-
if (success) {
|
|
142
|
-
const newCall = {
|
|
143
|
-
uuid: callUUID,
|
|
144
|
-
handle: callHandle,
|
|
145
|
-
displayName: callDisplayName,
|
|
146
|
-
isActive: false,
|
|
147
|
-
direction: 'outgoing',
|
|
148
|
-
};
|
|
149
|
-
setActiveCalls((prev) => [...prev, newCall]);
|
|
150
|
-
// Store mapping between CallKit UUID and Telnyx call for later reference
|
|
151
|
-
call._callKitUUID = callUUID;
|
|
152
|
-
return callUUID;
|
|
153
|
-
}
|
|
154
|
-
return null;
|
|
155
|
-
}, []);
|
|
156
|
-
// Report an incoming call
|
|
157
|
-
const reportIncomingCall = (0, react_1.useCallback)(async (call, handle, displayName) => {
|
|
158
|
-
if (!callkit_1.default.isAvailable()) {
|
|
159
|
-
console.warn('CallKit: Not available, cannot report incoming call');
|
|
160
|
-
return null;
|
|
161
|
-
}
|
|
162
|
-
const callUUID = callkit_1.default.generateCallUUID();
|
|
163
|
-
const callHandle = handle || call.destinationNumber || call.callId || 'Unknown';
|
|
164
|
-
const callDisplayName = displayName || callHandle;
|
|
165
|
-
console.log('useCallKit: Reporting incoming call', {
|
|
166
|
-
callUUID,
|
|
167
|
-
callHandle,
|
|
168
|
-
callDisplayName,
|
|
169
|
-
telnyxCallId: call.callId,
|
|
170
|
-
});
|
|
171
|
-
const success = await callkit_1.default.reportIncomingCall(
|
|
172
|
-
callUUID,
|
|
173
|
-
callHandle,
|
|
174
|
-
callDisplayName
|
|
175
|
-
);
|
|
176
|
-
if (success) {
|
|
177
|
-
const newCall = {
|
|
178
|
-
uuid: callUUID,
|
|
179
|
-
handle: callHandle,
|
|
180
|
-
displayName: callDisplayName,
|
|
181
|
-
isActive: false,
|
|
182
|
-
direction: 'incoming',
|
|
183
|
-
};
|
|
184
|
-
setActiveCalls((prev) => [...prev, newCall]);
|
|
185
|
-
// Store mapping between CallKit UUID and Telnyx call for later reference
|
|
186
|
-
call._callKitUUID = callUUID;
|
|
187
|
-
return callUUID;
|
|
188
|
-
}
|
|
189
|
-
return null;
|
|
190
|
-
}, []);
|
|
191
|
-
// End a call
|
|
192
|
-
const endCall = (0, react_1.useCallback)(
|
|
193
|
-
async (callUUID, reason = callkit_1.CallEndReason.RemoteEnded) => {
|
|
194
|
-
if (!callkit_1.default.isAvailable()) {
|
|
195
|
-
return false;
|
|
196
|
-
}
|
|
197
|
-
console.log('useCallKit: Ending call', { callUUID, reason });
|
|
198
|
-
try {
|
|
199
|
-
// For incoming calls, we should use reportCallEnded (which dismisses the UI)
|
|
200
|
-
// For outgoing calls, we should use endCall (which sends the end request)
|
|
201
|
-
// Check if this is likely an incoming call by looking at our active calls
|
|
202
|
-
const activeCall = activeCallsRef.current.find((call) => call.uuid === callUUID);
|
|
203
|
-
const isIncomingCall = activeCall?.direction === 'incoming';
|
|
204
|
-
if (isIncomingCall) {
|
|
205
|
-
await callkit_1.default.reportCallEnded(callUUID, reason);
|
|
206
|
-
} else {
|
|
207
|
-
await callkit_1.default.endCall(callUUID);
|
|
40
|
+
const { onAnswerCall, onEndCall, onStartCall } = options;
|
|
41
|
+
const [activeCalls, setActiveCalls] = (0, react_1.useState)([]);
|
|
42
|
+
const [isAvailable, setIsAvailable] = (0, react_1.useState)(false);
|
|
43
|
+
// Use refs to store stable callback references and current state
|
|
44
|
+
const onAnswerCallRef = (0, react_1.useRef)(onAnswerCall);
|
|
45
|
+
const onEndCallRef = (0, react_1.useRef)(onEndCall);
|
|
46
|
+
const onStartCallRef = (0, react_1.useRef)(onStartCall);
|
|
47
|
+
const activeCallsRef = (0, react_1.useRef)(activeCalls);
|
|
48
|
+
// Update refs when callbacks change
|
|
49
|
+
(0, react_1.useEffect)(() => {
|
|
50
|
+
onAnswerCallRef.current = onAnswerCall;
|
|
51
|
+
}, [onAnswerCall]);
|
|
52
|
+
(0, react_1.useEffect)(() => {
|
|
53
|
+
onEndCallRef.current = onEndCall;
|
|
54
|
+
}, [onEndCall]);
|
|
55
|
+
(0, react_1.useEffect)(() => {
|
|
56
|
+
onStartCallRef.current = onStartCall;
|
|
57
|
+
}, [onStartCall]);
|
|
58
|
+
// Update active calls ref
|
|
59
|
+
(0, react_1.useEffect)(() => {
|
|
60
|
+
activeCallsRef.current = activeCalls;
|
|
61
|
+
}, [activeCalls]);
|
|
62
|
+
(0, react_1.useEffect)(() => {
|
|
63
|
+
setIsAvailable(callkit_1.default.isAvailable());
|
|
64
|
+
if (!callkit_1.default.isAvailable()) {
|
|
65
|
+
console.log('CallKit: Not available on this platform');
|
|
66
|
+
return;
|
|
208
67
|
}
|
|
209
|
-
//
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
const updateCall = (0, react_1.useCallback)(async (callUUID, displayName, handle) => {
|
|
240
|
-
if (!callkit_1.default.isAvailable()) {
|
|
241
|
-
return false;
|
|
242
|
-
}
|
|
243
|
-
console.log('useCallKit: Updating call', { callUUID, displayName, handle });
|
|
244
|
-
const success = await callkit_1.default.updateCall(callUUID, displayName, handle);
|
|
245
|
-
if (success) {
|
|
246
|
-
// Update our local state
|
|
247
|
-
setActiveCalls((prev) =>
|
|
248
|
-
prev.map((call) => (call.uuid === callUUID ? { ...call, displayName, handle } : call))
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
return success;
|
|
252
|
-
}, []);
|
|
253
|
-
// Answer a call
|
|
254
|
-
const answerCall = (0, react_1.useCallback)(async (callUUID) => {
|
|
255
|
-
if (!callkit_1.default.isAvailable()) {
|
|
256
|
-
return false;
|
|
257
|
-
}
|
|
258
|
-
console.log('useCallKit: Answering call', { callUUID });
|
|
259
|
-
const success = await callkit_1.default.answerCall(callUUID);
|
|
260
|
-
if (success) {
|
|
261
|
-
// Update our local state to mark call as active
|
|
262
|
-
setActiveCalls((prev) =>
|
|
263
|
-
prev.map((call) => (call.uuid === callUUID ? { ...call, isActive: true } : call))
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
return success;
|
|
267
|
-
}, []);
|
|
268
|
-
// Get CallKit UUID for a Telnyx call
|
|
269
|
-
const getCallKitUUID = (0, react_1.useCallback)((call) => {
|
|
270
|
-
return call._callKitUUID || null;
|
|
271
|
-
}, []);
|
|
272
|
-
// Set up automatic CallKit integration for a Telnyx call
|
|
273
|
-
const integrateCall = (0, react_1.useCallback)(
|
|
274
|
-
async (call, direction) => {
|
|
275
|
-
if (!callkit_1.default.isAvailable()) {
|
|
276
|
-
return null;
|
|
277
|
-
}
|
|
278
|
-
let callUUID = null;
|
|
279
|
-
if (direction === 'incoming') {
|
|
280
|
-
callUUID = await reportIncomingCall(call);
|
|
281
|
-
} else {
|
|
282
|
-
callUUID = await startOutgoingCall(call);
|
|
283
|
-
}
|
|
284
|
-
if (callUUID) {
|
|
285
|
-
// Set up automatic state reporting
|
|
286
|
-
const handleStateChange = async (call, state) => {
|
|
287
|
-
if (state === 'active') {
|
|
288
|
-
await reportCallConnected(callUUID);
|
|
289
|
-
} else if (state === 'ended' || state === 'failed') {
|
|
290
|
-
const reason =
|
|
291
|
-
state === 'failed'
|
|
292
|
-
? callkit_1.CallEndReason.Failed
|
|
293
|
-
: callkit_1.CallEndReason.RemoteEnded;
|
|
294
|
-
await endCall(callUUID, reason);
|
|
295
|
-
}
|
|
68
|
+
// Load existing active calls only once
|
|
69
|
+
const loadActiveCalls = async () => {
|
|
70
|
+
const calls = await callkit_1.default.getActiveCalls();
|
|
71
|
+
setActiveCalls(calls.map((call) => ({
|
|
72
|
+
uuid: call.uuid,
|
|
73
|
+
handle: call.handle || call.caller || 'Unknown',
|
|
74
|
+
displayName: call.caller || call.displayName || 'Unknown Caller',
|
|
75
|
+
isActive: true,
|
|
76
|
+
direction: call.direction || 'incoming',
|
|
77
|
+
})));
|
|
78
|
+
};
|
|
79
|
+
loadActiveCalls();
|
|
80
|
+
// Set up event listeners using stable refs
|
|
81
|
+
const unsubscribeAnswer = callkit_1.default.onAnswerCall((event) => {
|
|
82
|
+
console.log('useCallKit: Call answered via CallKit', event);
|
|
83
|
+
onAnswerCallRef.current?.(event.callUUID);
|
|
84
|
+
});
|
|
85
|
+
const unsubscribeEnd = callkit_1.default.onEndCall((event) => {
|
|
86
|
+
console.log('useCallKit: Call ended via CallKit', event);
|
|
87
|
+
setActiveCalls((prev) => prev.filter((call) => call.uuid !== event.callUUID));
|
|
88
|
+
onEndCallRef.current?.(event.callUUID);
|
|
89
|
+
});
|
|
90
|
+
const unsubscribeStart = callkit_1.default.onStartCall((event) => {
|
|
91
|
+
console.log('useCallKit: Call started via CallKit', event);
|
|
92
|
+
onStartCallRef.current?.(event.callUUID);
|
|
93
|
+
});
|
|
94
|
+
return () => {
|
|
95
|
+
unsubscribeAnswer();
|
|
96
|
+
unsubscribeEnd();
|
|
97
|
+
unsubscribeStart();
|
|
296
98
|
};
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
99
|
+
}, []); // Empty dependency array - only run once
|
|
100
|
+
// Start an outgoing call
|
|
101
|
+
const startOutgoingCall = (0, react_1.useCallback)(async (call, handle, displayName) => {
|
|
102
|
+
if (!callkit_1.default.isAvailable()) {
|
|
103
|
+
console.warn('CallKit: Not available, cannot start outgoing call');
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
const callUUID = callkit_1.default.generateCallUUID();
|
|
107
|
+
const callHandle = handle || call.destinationNumber || 'Unknown';
|
|
108
|
+
const callDisplayName = displayName || callHandle;
|
|
109
|
+
console.log('useCallKit: Starting outgoing call', {
|
|
110
|
+
callUUID,
|
|
111
|
+
callHandle,
|
|
112
|
+
callDisplayName,
|
|
113
|
+
telnyxCallId: call.callId,
|
|
114
|
+
});
|
|
115
|
+
const success = await callkit_1.default.startOutgoingCall(callUUID, callHandle, callDisplayName);
|
|
116
|
+
if (success) {
|
|
117
|
+
const newCall = {
|
|
118
|
+
uuid: callUUID,
|
|
119
|
+
handle: callHandle,
|
|
120
|
+
displayName: callDisplayName,
|
|
121
|
+
isActive: false,
|
|
122
|
+
direction: 'outgoing',
|
|
123
|
+
};
|
|
124
|
+
setActiveCalls((prev) => [...prev, newCall]);
|
|
125
|
+
// Store mapping between CallKit UUID and Telnyx call for later reference
|
|
126
|
+
call._callKitUUID = callUUID;
|
|
127
|
+
return callUUID;
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}, []);
|
|
131
|
+
// Report an incoming call
|
|
132
|
+
const reportIncomingCall = (0, react_1.useCallback)(async (call, handle, displayName) => {
|
|
133
|
+
if (!callkit_1.default.isAvailable()) {
|
|
134
|
+
console.warn('CallKit: Not available, cannot report incoming call');
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
const callUUID = callkit_1.default.generateCallUUID();
|
|
138
|
+
const callHandle = handle || call.destinationNumber || call.callId || 'Unknown';
|
|
139
|
+
const callDisplayName = displayName || callHandle;
|
|
140
|
+
console.log('useCallKit: Reporting incoming call', {
|
|
141
|
+
callUUID,
|
|
142
|
+
callHandle,
|
|
143
|
+
callDisplayName,
|
|
144
|
+
telnyxCallId: call.callId,
|
|
145
|
+
});
|
|
146
|
+
const success = await callkit_1.default.reportIncomingCall(callUUID, callHandle, callDisplayName);
|
|
147
|
+
if (success) {
|
|
148
|
+
const newCall = {
|
|
149
|
+
uuid: callUUID,
|
|
150
|
+
handle: callHandle,
|
|
151
|
+
displayName: callDisplayName,
|
|
152
|
+
isActive: false,
|
|
153
|
+
direction: 'incoming',
|
|
154
|
+
};
|
|
155
|
+
setActiveCalls((prev) => [...prev, newCall]);
|
|
156
|
+
// Store mapping between CallKit UUID and Telnyx call for later reference
|
|
157
|
+
call._callKitUUID = callUUID;
|
|
158
|
+
return callUUID;
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}, []);
|
|
162
|
+
// End a call
|
|
163
|
+
const endCall = (0, react_1.useCallback)(async (callUUID, reason = callkit_1.CallEndReason.RemoteEnded) => {
|
|
164
|
+
if (!callkit_1.default.isAvailable()) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
console.log('useCallKit: Ending call', { callUUID, reason });
|
|
168
|
+
try {
|
|
169
|
+
// For incoming calls, we should use reportCallEnded (which dismisses the UI)
|
|
170
|
+
// For outgoing calls, we should use endCall (which sends the end request)
|
|
171
|
+
// Check if this is likely an incoming call by looking at our active calls
|
|
172
|
+
const activeCall = activeCallsRef.current.find((call) => call.uuid === callUUID);
|
|
173
|
+
const isIncomingCall = activeCall?.direction === 'incoming';
|
|
174
|
+
if (isIncomingCall) {
|
|
175
|
+
await callkit_1.default.reportCallEnded(callUUID, reason);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
await callkit_1.default.endCall(callUUID);
|
|
179
|
+
}
|
|
180
|
+
// Update our local state
|
|
181
|
+
setActiveCalls((prev) => prev.filter((call) => call.uuid !== callUUID));
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
console.log('useCallKit: Error ending call (may already be ended):', error);
|
|
186
|
+
// Still remove from our local state even if CallKit operation failed
|
|
187
|
+
// This ensures our UI stays in sync
|
|
188
|
+
setActiveCalls((prev) => prev.filter((call) => call.uuid !== callUUID));
|
|
189
|
+
// Return true since the call is effectively ended from our perspective
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
}, []);
|
|
193
|
+
// Report call connected
|
|
194
|
+
const reportCallConnected = (0, react_1.useCallback)(async (callUUID) => {
|
|
195
|
+
if (!callkit_1.default.isAvailable()) {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
console.log('useCallKit: Reporting call connected', { callUUID });
|
|
199
|
+
const success = await callkit_1.default.reportCallConnected(callUUID);
|
|
200
|
+
if (success) {
|
|
201
|
+
// Update our local state to mark the call as active
|
|
202
|
+
setActiveCalls((prev) => prev.map((call) => (call.uuid === callUUID ? { ...call, isActive: true } : call)));
|
|
203
|
+
}
|
|
204
|
+
return success;
|
|
205
|
+
}, []);
|
|
206
|
+
// Update call information
|
|
207
|
+
const updateCall = (0, react_1.useCallback)(async (callUUID, displayName, handle) => {
|
|
208
|
+
if (!callkit_1.default.isAvailable()) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
console.log('useCallKit: Updating call', { callUUID, displayName, handle });
|
|
212
|
+
const success = await callkit_1.default.updateCall(callUUID, displayName, handle);
|
|
213
|
+
if (success) {
|
|
214
|
+
// Update our local state
|
|
215
|
+
setActiveCalls((prev) => prev.map((call) => (call.uuid === callUUID ? { ...call, displayName, handle } : call)));
|
|
216
|
+
}
|
|
217
|
+
return success;
|
|
218
|
+
}, []);
|
|
219
|
+
// Answer a call
|
|
220
|
+
const answerCall = (0, react_1.useCallback)(async (callUUID) => {
|
|
221
|
+
if (!callkit_1.default.isAvailable()) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
console.log('useCallKit: Answering call', { callUUID });
|
|
225
|
+
const success = await callkit_1.default.answerCall(callUUID);
|
|
226
|
+
if (success) {
|
|
227
|
+
// Update our local state to mark call as active
|
|
228
|
+
setActiveCalls((prev) => prev.map((call) => (call.uuid === callUUID ? { ...call, isActive: true } : call)));
|
|
229
|
+
}
|
|
230
|
+
return success;
|
|
231
|
+
}, []);
|
|
232
|
+
// Get CallKit UUID for a Telnyx call
|
|
233
|
+
const getCallKitUUID = (0, react_1.useCallback)((call) => {
|
|
234
|
+
return call._callKitUUID || null;
|
|
235
|
+
}, []);
|
|
236
|
+
// Set up automatic CallKit integration for a Telnyx call
|
|
237
|
+
const integrateCall = (0, react_1.useCallback)(async (call, direction) => {
|
|
238
|
+
if (!callkit_1.default.isAvailable()) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
let callUUID = null;
|
|
242
|
+
if (direction === 'incoming') {
|
|
243
|
+
callUUID = await reportIncomingCall(call);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
callUUID = await startOutgoingCall(call);
|
|
247
|
+
}
|
|
248
|
+
if (callUUID) {
|
|
249
|
+
// Set up automatic state reporting
|
|
250
|
+
const handleStateChange = async (call, state) => {
|
|
251
|
+
if (state === 'active') {
|
|
252
|
+
await reportCallConnected(callUUID);
|
|
253
|
+
}
|
|
254
|
+
else if (state === 'ended' || state === 'failed') {
|
|
255
|
+
const reason = state === 'failed' ? callkit_1.CallEndReason.Failed : callkit_1.CallEndReason.RemoteEnded;
|
|
256
|
+
await endCall(callUUID, reason);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
call.on('telnyx.call.state', handleStateChange);
|
|
260
|
+
}
|
|
261
|
+
return callUUID;
|
|
262
|
+
}, [reportIncomingCall, startOutgoingCall, reportCallConnected, endCall]);
|
|
263
|
+
return {
|
|
264
|
+
// State
|
|
265
|
+
isAvailable,
|
|
266
|
+
activeCalls,
|
|
267
|
+
// Methods
|
|
268
|
+
startOutgoingCall,
|
|
269
|
+
reportIncomingCall,
|
|
270
|
+
answerCall,
|
|
271
|
+
endCall,
|
|
272
|
+
reportCallConnected,
|
|
273
|
+
updateCall,
|
|
274
|
+
getCallKitUUID,
|
|
275
|
+
integrateCall,
|
|
276
|
+
// Utility
|
|
277
|
+
generateCallUUID: callkit_1.default.generateCallUUID,
|
|
278
|
+
};
|
|
319
279
|
}
|
|
@@ -2,17 +2,17 @@ import React from 'react';
|
|
|
2
2
|
import { TelnyxVoipClient } from '../telnyx-voip-client';
|
|
3
3
|
import { TelnyxConnectionState } from '../models/connection-state';
|
|
4
4
|
interface TelnyxVoiceContextValue {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
voipClient: TelnyxVoipClient;
|
|
6
|
+
connectionState?: TelnyxConnectionState;
|
|
7
|
+
setConnectionState?: (state: TelnyxConnectionState) => void;
|
|
8
|
+
connect?: (payload: any) => Promise<any>;
|
|
9
|
+
client?: any;
|
|
10
|
+
setClient?: (client: any) => void;
|
|
11
|
+
enableAutoReconnect?: (enabled: boolean) => void;
|
|
12
12
|
}
|
|
13
13
|
export declare const TelnyxVoiceProvider: React.FC<{
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
voipClient: TelnyxVoipClient;
|
|
15
|
+
children: React.ReactNode;
|
|
16
16
|
}>;
|
|
17
17
|
export declare const useTelnyxVoice: () => TelnyxVoiceContextValue;
|
|
18
18
|
export {};
|
|
@@ -1,21 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports,
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.useTelnyxVoice = exports.TelnyxVoiceProvider = void 0;
|
|
4
|
-
const jsx_runtime_1 = require(
|
|
5
|
-
const react_1 = require(
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
6
|
const TelnyxVoiceContext = (0, react_1.createContext)(null);
|
|
7
7
|
const TelnyxVoiceProvider = ({ voipClient, children }) => {
|
|
8
|
-
|
|
9
|
-
value: { voipClient },
|
|
10
|
-
children: children,
|
|
11
|
-
});
|
|
8
|
+
return ((0, jsx_runtime_1.jsx)(TelnyxVoiceContext.Provider, { value: { voipClient }, children: children }));
|
|
12
9
|
};
|
|
13
10
|
exports.TelnyxVoiceProvider = TelnyxVoiceProvider;
|
|
14
11
|
const useTelnyxVoice = () => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
const context = (0, react_1.useContext)(TelnyxVoiceContext);
|
|
13
|
+
if (!context) {
|
|
14
|
+
throw new Error('useTelnyxVoice must be used within a TelnyxVoiceProvider');
|
|
15
|
+
}
|
|
16
|
+
return context;
|
|
20
17
|
};
|
|
21
18
|
exports.useTelnyxVoice = useTelnyxVoice;
|