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

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 (47) hide show
  1. package/README.md +483 -0
  2. package/TelnyxVoiceCommons.podspec +31 -31
  3. package/ios/CallKitBridge.m +43 -43
  4. package/ios/CallKitBridge.swift +879 -879
  5. package/ios/VoicePnBridge.m +30 -30
  6. package/ios/VoicePnBridge.swift +86 -86
  7. package/lib/callkit/callkit-coordinator.d.ts +117 -113
  8. package/lib/callkit/callkit-coordinator.js +727 -681
  9. package/lib/callkit/callkit.d.ts +41 -41
  10. package/lib/callkit/callkit.js +242 -252
  11. package/lib/callkit/index.js +47 -15
  12. package/lib/callkit/use-callkit.d.ts +19 -19
  13. package/lib/callkit/use-callkit.js +310 -270
  14. package/lib/context/TelnyxVoiceContext.d.ts +9 -9
  15. package/lib/context/TelnyxVoiceContext.js +13 -10
  16. package/lib/hooks/use-callkit-coordinator.d.ts +17 -9
  17. package/lib/hooks/use-callkit-coordinator.js +50 -45
  18. package/lib/hooks/useAppReadyNotifier.js +15 -13
  19. package/lib/hooks/useAppStateHandler.d.ts +11 -6
  20. package/lib/hooks/useAppStateHandler.js +110 -95
  21. package/lib/index.d.ts +21 -3
  22. package/lib/index.js +201 -50
  23. package/lib/internal/CallKitHandler.d.ts +6 -6
  24. package/lib/internal/CallKitHandler.js +104 -96
  25. package/lib/internal/callkit-manager.d.ts +57 -57
  26. package/lib/internal/callkit-manager.js +316 -299
  27. package/lib/internal/calls/call-state-controller.d.ts +86 -81
  28. package/lib/internal/calls/call-state-controller.js +307 -269
  29. package/lib/internal/session/session-manager.d.ts +75 -75
  30. package/lib/internal/session/session-manager.js +424 -350
  31. package/lib/internal/user-defaults-helpers.js +39 -49
  32. package/lib/internal/voice-pn-bridge.d.ts +11 -11
  33. package/lib/internal/voice-pn-bridge.js +3 -3
  34. package/lib/models/call-state.d.ts +44 -44
  35. package/lib/models/call-state.js +68 -66
  36. package/lib/models/call.d.ts +133 -133
  37. package/lib/models/call.js +382 -354
  38. package/lib/models/config.d.ts +18 -11
  39. package/lib/models/config.js +35 -37
  40. package/lib/models/connection-state.d.ts +10 -10
  41. package/lib/models/connection-state.js +16 -16
  42. package/lib/telnyx-voice-app.d.ts +28 -28
  43. package/lib/telnyx-voice-app.js +482 -424
  44. package/lib/telnyx-voip-client.d.ts +167 -155
  45. package/lib/telnyx-voip-client.js +392 -331
  46. package/package.json +1 -1
  47. package/src/telnyx-voip-client.ts +64 -0
@@ -1,13 +1,21 @@
1
1
  import { Call } from '@telnyx/react-native-voice-sdk';
2
2
  import { TelnyxVoipClient } from '../telnyx-voip-client';
3
3
  export declare function useCallKitCoordinator(): {
4
- reportIncomingCall: (call: Call, callerName: string, callerNumber: string) => Promise<string | null>;
5
- startOutgoingCall: (call: Call, destinationNumber: string, displayName?: string) => Promise<string | null>;
6
- answerCallFromUI: (call: Call) => Promise<boolean>;
7
- endCallFromUI: (call: Call) => Promise<boolean>;
8
- getCallKitUUID: (call: Call) => string | null;
9
- getWebRTCCall: (callKitUUID: string) => Call | null;
10
- linkExistingCallKitCall: (call: Call, callKitUUID: string) => void;
11
- isAvailable: () => boolean;
12
- setVoipClient: (voipClient: TelnyxVoipClient) => void;
4
+ reportIncomingCall: (
5
+ call: Call,
6
+ callerName: string,
7
+ callerNumber: string
8
+ ) => Promise<string | null>;
9
+ startOutgoingCall: (
10
+ call: Call,
11
+ destinationNumber: string,
12
+ displayName?: string
13
+ ) => Promise<string | null>;
14
+ answerCallFromUI: (call: Call) => Promise<boolean>;
15
+ endCallFromUI: (call: Call) => Promise<boolean>;
16
+ getCallKitUUID: (call: Call) => string | null;
17
+ getWebRTCCall: (callKitUUID: string) => Call | null;
18
+ linkExistingCallKitCall: (call: Call, callKitUUID: string) => void;
19
+ isAvailable: () => boolean;
20
+ setVoipClient: (voipClient: TelnyxVoipClient) => void;
13
21
  };
@@ -1,48 +1,53 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ 'use strict';
2
+ var __importDefault =
3
+ (this && this.__importDefault) ||
4
+ function (mod) {
5
+ return mod && mod.__esModule ? mod : { default: mod };
6
+ };
7
+ Object.defineProperty(exports, '__esModule', { value: true });
6
8
  exports.useCallKitCoordinator = useCallKitCoordinator;
7
- const react_1 = require("react");
8
- const callkit_coordinator_1 = __importDefault(require("../callkit/callkit-coordinator"));
9
+ const react_1 = require('react');
10
+ const callkit_coordinator_1 = __importDefault(require('../callkit/callkit-coordinator'));
9
11
  function useCallKitCoordinator() {
10
- const reportIncomingCall = (0, react_1.useCallback)(async (call, callerName, callerNumber) => {
11
- return callkit_coordinator_1.default.reportIncomingCall(call, callerName, callerNumber);
12
- }, []);
13
- const startOutgoingCall = (0, react_1.useCallback)(async (call, destinationNumber, displayName) => {
14
- return callkit_coordinator_1.default.startOutgoingCall(call, destinationNumber, displayName);
15
- }, []);
16
- const answerCallFromUI = (0, react_1.useCallback)(async (call) => {
17
- return callkit_coordinator_1.default.answerCallFromUI(call);
18
- }, []);
19
- const endCallFromUI = (0, react_1.useCallback)(async (call) => {
20
- return callkit_coordinator_1.default.endCallFromUI(call);
21
- }, []);
22
- const getCallKitUUID = (0, react_1.useCallback)((call) => {
23
- return callkit_coordinator_1.default.getCallKitUUID(call);
24
- }, []);
25
- const getWebRTCCall = (0, react_1.useCallback)((callKitUUID) => {
26
- return callkit_coordinator_1.default.getWebRTCCall(callKitUUID);
27
- }, []);
28
- const linkExistingCallKitCall = (0, react_1.useCallback)((call, callKitUUID) => {
29
- callkit_coordinator_1.default.linkExistingCallKitCall(call, callKitUUID);
30
- }, []);
31
- const isAvailable = (0, react_1.useCallback)(() => {
32
- return callkit_coordinator_1.default.isAvailable();
33
- }, []);
34
- const setVoipClient = (0, react_1.useCallback)((voipClient) => {
35
- callkit_coordinator_1.default.setVoipClient(voipClient);
36
- }, []);
37
- return {
38
- reportIncomingCall,
39
- startOutgoingCall,
40
- answerCallFromUI,
41
- endCallFromUI,
42
- getCallKitUUID,
43
- getWebRTCCall,
44
- linkExistingCallKitCall,
45
- isAvailable,
46
- setVoipClient,
47
- };
12
+ const reportIncomingCall = (0, react_1.useCallback)(async (call, callerName, callerNumber) => {
13
+ return callkit_coordinator_1.default.reportIncomingCall(call, callerName, callerNumber);
14
+ }, []);
15
+ const startOutgoingCall = (0, react_1.useCallback)(
16
+ async (call, destinationNumber, displayName) => {
17
+ return callkit_coordinator_1.default.startOutgoingCall(call, destinationNumber, displayName);
18
+ },
19
+ []
20
+ );
21
+ const answerCallFromUI = (0, react_1.useCallback)(async (call) => {
22
+ return callkit_coordinator_1.default.answerCallFromUI(call);
23
+ }, []);
24
+ const endCallFromUI = (0, react_1.useCallback)(async (call) => {
25
+ return callkit_coordinator_1.default.endCallFromUI(call);
26
+ }, []);
27
+ const getCallKitUUID = (0, react_1.useCallback)((call) => {
28
+ return callkit_coordinator_1.default.getCallKitUUID(call);
29
+ }, []);
30
+ const getWebRTCCall = (0, react_1.useCallback)((callKitUUID) => {
31
+ return callkit_coordinator_1.default.getWebRTCCall(callKitUUID);
32
+ }, []);
33
+ const linkExistingCallKitCall = (0, react_1.useCallback)((call, callKitUUID) => {
34
+ callkit_coordinator_1.default.linkExistingCallKitCall(call, callKitUUID);
35
+ }, []);
36
+ const isAvailable = (0, react_1.useCallback)(() => {
37
+ return callkit_coordinator_1.default.isAvailable();
38
+ }, []);
39
+ const setVoipClient = (0, react_1.useCallback)((voipClient) => {
40
+ callkit_coordinator_1.default.setVoipClient(voipClient);
41
+ }, []);
42
+ return {
43
+ reportIncomingCall,
44
+ startOutgoingCall,
45
+ answerCallFromUI,
46
+ endCallFromUI,
47
+ getCallKitUUID,
48
+ getWebRTCCall,
49
+ linkExistingCallKitCall,
50
+ isAvailable,
51
+ setVoipClient,
52
+ };
48
53
  }
@@ -1,8 +1,8 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ 'use strict';
2
+ Object.defineProperty(exports, '__esModule', { value: true });
3
3
  exports.useAppReadyNotifier = void 0;
4
- const react_1 = require("react");
5
- const react_native_1 = require("react-native");
4
+ const react_1 = require('react');
5
+ const react_native_1 = require('react-native');
6
6
  /**
7
7
  * Hook to notify the native side when React Native is ready
8
8
  * Call this hook when your main screen/login screen is visible and ready
@@ -12,14 +12,16 @@ const react_native_1 = require("react-native");
12
12
  * handled automatically by the native Android services, so this hook is simplified.
13
13
  */
14
14
  const useAppReadyNotifier = () => {
15
- (0, react_1.useEffect)(() => {
16
- // Only notify on Android since this is Android-specific functionality
17
- if (react_native_1.Platform.OS === 'android') {
18
- console.log('useAppReadyNotifier: React Native is ready (native services handle FCM automatically)');
19
- // Note: The VoicePnManager in the native Android code automatically handles
20
- // push notification state when the Firebase messaging service receives notifications.
21
- // No JavaScript module communication is needed anymore.
22
- }
23
- }, []);
15
+ (0, react_1.useEffect)(() => {
16
+ // Only notify on Android since this is Android-specific functionality
17
+ if (react_native_1.Platform.OS === 'android') {
18
+ console.log(
19
+ 'useAppReadyNotifier: React Native is ready (native services handle FCM automatically)'
20
+ );
21
+ // Note: The VoicePnManager in the native Android code automatically handles
22
+ // push notification state when the Firebase messaging service receives notifications.
23
+ // No JavaScript module communication is needed anymore.
24
+ }
25
+ }, []);
24
26
  };
25
27
  exports.useAppReadyNotifier = useAppReadyNotifier;
@@ -1,16 +1,21 @@
1
1
  import { AppStateStatus } from 'react-native';
2
2
  import { TelnyxVoipClient } from '../telnyx-voip-client';
3
3
  interface UseAppStateHandlerOptions {
4
- voipClient: TelnyxVoipClient;
5
- disconnectOnBackground?: boolean;
6
- navigateToLoginOnDisconnect?: boolean;
7
- debug?: boolean;
4
+ voipClient: TelnyxVoipClient;
5
+ disconnectOnBackground?: boolean;
6
+ navigateToLoginOnDisconnect?: boolean;
7
+ debug?: boolean;
8
8
  }
9
9
  /**
10
10
  * Hook to handle app state changes for VoIP behavior
11
11
  * When app goes to background without an active call, disconnect socket and redirect to login
12
12
  */
13
- export declare const useAppStateHandler: ({ voipClient, disconnectOnBackground, navigateToLoginOnDisconnect, debug, }: UseAppStateHandlerOptions) => {
14
- currentAppState: AppStateStatus;
13
+ export declare const useAppStateHandler: ({
14
+ voipClient,
15
+ disconnectOnBackground,
16
+ navigateToLoginOnDisconnect,
17
+ debug,
18
+ }: UseAppStateHandlerOptions) => {
19
+ currentAppState: AppStateStatus;
15
20
  };
16
21
  export {};
@@ -1,105 +1,120 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ 'use strict';
2
+ var __importDefault =
3
+ (this && this.__importDefault) ||
4
+ function (mod) {
5
+ return mod && mod.__esModule ? mod : { default: mod };
6
+ };
7
+ Object.defineProperty(exports, '__esModule', { value: true });
6
8
  exports.useAppStateHandler = void 0;
7
- const react_1 = require("react");
8
- const react_native_1 = require("react-native");
9
- const expo_router_1 = require("expo-router");
10
- const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
11
- const connection_state_1 = require("../models/connection-state");
12
- const call_state_1 = require("../models/call-state");
9
+ const react_1 = require('react');
10
+ const react_native_1 = require('react-native');
11
+ const expo_router_1 = require('expo-router');
12
+ const async_storage_1 = __importDefault(require('@react-native-async-storage/async-storage'));
13
+ const connection_state_1 = require('../models/connection-state');
14
+ const call_state_1 = require('../models/call-state');
13
15
  /**
14
16
  * Hook to handle app state changes for VoIP behavior
15
17
  * When app goes to background without an active call, disconnect socket and redirect to login
16
18
  */
17
- const useAppStateHandler = ({ voipClient, disconnectOnBackground = true, navigateToLoginOnDisconnect = true, debug = false, }) => {
18
- const appState = (0, react_1.useRef)(react_native_1.AppState.currentState);
19
- const log = debug ? console.log : () => { };
20
- (0, react_1.useEffect)(() => {
21
- const handleAppStateChange = async (nextAppState) => {
22
- log('AppStateHandler: App state changed from', appState.current, 'to', nextAppState);
23
- // When app goes to background
24
- if (appState.current.match(/active/) && nextAppState === 'background') {
25
- log('AppStateHandler: App went to background, checking for active calls...');
26
- const connectionState = voipClient.currentConnectionState;
27
- if (connectionState !== connection_state_1.TelnyxConnectionState.CONNECTED) {
28
- log('AppStateHandler: Not connected, skipping background handling');
29
- appState.current = nextAppState;
30
- return;
31
- }
32
- // Check if there's an active call (including ringing calls)
33
- const activeCalls = voipClient.currentCalls;
34
- const hasActiveCall = activeCalls.length > 0 &&
35
- activeCalls.some((call) => call_state_1.CallStateHelpers.isActive(call.currentState) ||
36
- call.currentState === call_state_1.TelnyxCallState.RINGING);
37
- log('AppStateHandler: Active call check:', {
38
- callCount: activeCalls.length,
39
- hasActiveCall,
40
- callStates: activeCalls.map((call) => ({
41
- callId: call.callId,
42
- currentState: call.currentState,
43
- destination: call.destination,
44
- isIncoming: call.isIncoming,
45
- })),
46
- });
47
- if (!hasActiveCall && disconnectOnBackground) {
48
- // Check if there's a push notification call in progress
49
- const isPushNotificationInProgress = await async_storage_1.default.getItem('@push_notification_payload');
50
- if (isPushNotificationInProgress) {
51
- log('AppStateHandler: Push notification call in progress, keeping socket connected');
52
- // Wait a bit longer before allowing disconnection to give time for WebRTC call to establish
53
- setTimeout(async () => {
54
- const stillInProgress = await async_storage_1.default.getItem('@push_notification_payload');
55
- if (!stillInProgress) {
56
- log('AppStateHandler: Push notification call completed, now disconnecting socket');
57
- await voipClient.logout();
58
- if (navigateToLoginOnDisconnect) {
59
- expo_router_1.router.replace('/');
60
- }
61
- }
62
- }, 5000); // Wait 5 seconds
63
- appState.current = nextAppState;
64
- return;
65
- }
66
- log('AppStateHandler: No active call detected, disconnecting socket...');
67
- try {
68
- // Disconnect the socket with background reason
69
- await voipClient.logout();
70
- log('AppStateHandler: Socket disconnected successfully');
71
- // Navigate to login screen
72
- if (navigateToLoginOnDisconnect) {
73
- // Use a small delay to ensure the disconnect completes
74
- setTimeout(() => {
75
- log('AppStateHandler: Navigating to login screen');
76
- expo_router_1.router.replace('/');
77
- }, 100);
78
- }
79
- }
80
- catch (error) {
81
- console.error('AppStateHandler: Error during background disconnect:', error);
82
- }
19
+ const useAppStateHandler = ({
20
+ voipClient,
21
+ disconnectOnBackground = true,
22
+ navigateToLoginOnDisconnect = true,
23
+ debug = false,
24
+ }) => {
25
+ const appState = (0, react_1.useRef)(react_native_1.AppState.currentState);
26
+ const log = debug ? console.log : () => {};
27
+ (0, react_1.useEffect)(() => {
28
+ const handleAppStateChange = async (nextAppState) => {
29
+ log('AppStateHandler: App state changed from', appState.current, 'to', nextAppState);
30
+ // When app goes to background
31
+ if (appState.current.match(/active/) && nextAppState === 'background') {
32
+ log('AppStateHandler: App went to background, checking for active calls...');
33
+ const connectionState = voipClient.currentConnectionState;
34
+ if (connectionState !== connection_state_1.TelnyxConnectionState.CONNECTED) {
35
+ log('AppStateHandler: Not connected, skipping background handling');
36
+ appState.current = nextAppState;
37
+ return;
38
+ }
39
+ // Check if there's an active call (including ringing calls)
40
+ const activeCalls = voipClient.currentCalls;
41
+ const hasActiveCall =
42
+ activeCalls.length > 0 &&
43
+ activeCalls.some(
44
+ (call) =>
45
+ call_state_1.CallStateHelpers.isActive(call.currentState) ||
46
+ call.currentState === call_state_1.TelnyxCallState.RINGING
47
+ );
48
+ log('AppStateHandler: Active call check:', {
49
+ callCount: activeCalls.length,
50
+ hasActiveCall,
51
+ callStates: activeCalls.map((call) => ({
52
+ callId: call.callId,
53
+ currentState: call.currentState,
54
+ destination: call.destination,
55
+ isIncoming: call.isIncoming,
56
+ })),
57
+ });
58
+ if (!hasActiveCall && disconnectOnBackground) {
59
+ // Check if there's a push notification call in progress
60
+ const isPushNotificationInProgress = await async_storage_1.default.getItem(
61
+ '@push_notification_payload'
62
+ );
63
+ if (isPushNotificationInProgress) {
64
+ log('AppStateHandler: Push notification call in progress, keeping socket connected');
65
+ // Wait a bit longer before allowing disconnection to give time for WebRTC call to establish
66
+ setTimeout(async () => {
67
+ const stillInProgress = await async_storage_1.default.getItem(
68
+ '@push_notification_payload'
69
+ );
70
+ if (!stillInProgress) {
71
+ log('AppStateHandler: Push notification call completed, now disconnecting socket');
72
+ await voipClient.logout();
73
+ if (navigateToLoginOnDisconnect) {
74
+ expo_router_1.router.replace('/');
83
75
  }
84
- else {
85
- log('AppStateHandler: Active call detected or disconnect disabled, keeping socket connected');
86
- }
87
- }
88
- // When app comes to foreground
89
- if (appState.current.match(/background/) && nextAppState === 'active') {
90
- log('AppStateHandler: App came to foreground');
91
- // User will need to manually login again when returning from background
92
- // Auto-login only happens for push notification calls
93
- }
76
+ }
77
+ }, 5000); // Wait 5 seconds
94
78
  appState.current = nextAppState;
95
- };
96
- const subscription = react_native_1.AppState.addEventListener('change', handleAppStateChange);
97
- return () => {
98
- subscription?.remove();
99
- };
100
- }, [voipClient, disconnectOnBackground, navigateToLoginOnDisconnect, log]);
101
- return {
102
- currentAppState: appState.current,
79
+ return;
80
+ }
81
+ log('AppStateHandler: No active call detected, disconnecting socket...');
82
+ try {
83
+ // Disconnect the socket with background reason
84
+ await voipClient.logout();
85
+ log('AppStateHandler: Socket disconnected successfully');
86
+ // Navigate to login screen
87
+ if (navigateToLoginOnDisconnect) {
88
+ // Use a small delay to ensure the disconnect completes
89
+ setTimeout(() => {
90
+ log('AppStateHandler: Navigating to login screen');
91
+ expo_router_1.router.replace('/');
92
+ }, 100);
93
+ }
94
+ } catch (error) {
95
+ console.error('AppStateHandler: Error during background disconnect:', error);
96
+ }
97
+ } else {
98
+ log(
99
+ 'AppStateHandler: Active call detected or disconnect disabled, keeping socket connected'
100
+ );
101
+ }
102
+ }
103
+ // When app comes to foreground
104
+ if (appState.current.match(/background/) && nextAppState === 'active') {
105
+ log('AppStateHandler: App came to foreground');
106
+ // User will need to manually login again when returning from background
107
+ // Auto-login only happens for push notification calls
108
+ }
109
+ appState.current = nextAppState;
110
+ };
111
+ const subscription = react_native_1.AppState.addEventListener('change', handleAppStateChange);
112
+ return () => {
113
+ subscription?.remove();
103
114
  };
115
+ }, [voipClient, disconnectOnBackground, navigateToLoginOnDisconnect, log]);
116
+ return {
117
+ currentAppState: appState.current,
118
+ };
104
119
  };
105
120
  exports.useAppStateHandler = useAppStateHandler;
package/lib/index.d.ts CHANGED
@@ -8,16 +8,34 @@
8
8
  * call state transitions, push notification processing, and native call UI
9
9
  * integration.
10
10
  */
11
- export { TelnyxVoipClient, createTelnyxVoipClient, createBackgroundTelnyxVoipClient, } from './telnyx-voip-client';
11
+ export {
12
+ TelnyxVoipClient,
13
+ createTelnyxVoipClient,
14
+ createBackgroundTelnyxVoipClient,
15
+ } from './telnyx-voip-client';
12
16
  export type { TelnyxVoipClientOptions } from './telnyx-voip-client';
13
17
  export { TelnyxVoiceApp } from './telnyx-voice-app';
14
18
  export type { TelnyxVoiceAppOptions, TelnyxVoiceAppProps } from './telnyx-voice-app';
15
19
  export { useAppStateHandler } from './hooks/useAppStateHandler';
16
20
  export { useTelnyxVoice } from './context/TelnyxVoiceContext';
17
21
  export { Call } from './models/call';
18
- export { TelnyxConnectionState, isTelnyxConnectionState, canMakeCalls, isConnected, isTransitioning, } from './models/connection-state';
22
+ export {
23
+ TelnyxConnectionState,
24
+ isTelnyxConnectionState,
25
+ canMakeCalls,
26
+ isConnected,
27
+ isTransitioning,
28
+ } from './models/connection-state';
19
29
  export { TelnyxCallState, isTelnyxCallState, CallStateHelpers } from './models/call-state';
20
- export { isCredentialConfig, isTokenConfig, validateConfig, validateCredentialConfig, validateTokenConfig, createCredentialConfig, createTokenConfig, } from './models/config';
30
+ export {
31
+ isCredentialConfig,
32
+ isTokenConfig,
33
+ validateConfig,
34
+ validateCredentialConfig,
35
+ validateTokenConfig,
36
+ createCredentialConfig,
37
+ createTokenConfig,
38
+ } from './models/config';
21
39
  export type { Config, CredentialConfig, TokenConfig } from './models/config';
22
40
  export type { Call as TelnyxCall } from '@telnyx/react-native-voice-sdk';
23
41
  export * from './callkit';