@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,18 +1,266 @@
1
- import { NativeModules } from 'react-native';
2
-
3
- export interface VoicePnBridgeInterface {
4
- getPendingPushAction(): Promise<{
5
- action: string | null;
6
- metadata: string | null;
7
- }>;
8
- setPendingPushAction(action: string, metadata: string): Promise<boolean>;
9
- clearPendingPushAction(): Promise<boolean>;
10
- // Additional UserDefaults methods
11
- getVoipToken(): Promise<string | null>;
12
- getPendingVoipPush(): Promise<string | null>;
13
- clearPendingVoipPush(): Promise<boolean>;
14
- getPendingVoipAction(): Promise<string | null>;
15
- clearPendingVoipAction(): Promise<boolean>;
16
- }
17
-
18
- export const VoicePnBridge: VoicePnBridgeInterface = NativeModules.VoicePnBridge;
1
+ import { NativeModules, DeviceEventEmitter, EmitterSubscription } from 'react-native';
2
+
3
+ export interface CallActionEvent {
4
+ action: string;
5
+ callId?: string;
6
+ timestamp: number;
7
+ }
8
+
9
+ export interface VoicePnBridgeInterface {
10
+ getPendingPushAction(): Promise<{
11
+ action: string | null;
12
+ metadata: string | null;
13
+ }>;
14
+ setPendingPushAction(action: string, metadata: string): Promise<boolean>;
15
+ clearPendingPushAction(): Promise<boolean>;
16
+
17
+ // Call action methods (reliable @ReactMethod pattern)
18
+ getPendingCallAction(): Promise<{
19
+ action: string | null;
20
+ callId: string | null;
21
+ timestamp: number | null;
22
+ }>;
23
+ clearPendingCallAction(): Promise<boolean>;
24
+
25
+ // Call control methods (Android specific)
26
+ endCall(callId: string | null): Promise<boolean>;
27
+ showOngoingCallNotification(
28
+ callerName: string | null,
29
+ callerNumber: string | null,
30
+ callId: string | null
31
+ ): Promise<boolean>;
32
+ hideOngoingCallNotification(): Promise<boolean>;
33
+ hideIncomingCallNotification(): Promise<boolean>;
34
+
35
+ // Additional UserDefaults methods
36
+ getVoipToken(): Promise<string | null>;
37
+ getPendingVoipPush(): Promise<string | null>;
38
+ clearPendingVoipPush(): Promise<boolean>;
39
+ getPendingVoipAction(): Promise<string | null>;
40
+ clearPendingVoipAction(): Promise<boolean>;
41
+ }
42
+
43
+ const NativeBridge: VoicePnBridgeInterface = NativeModules.VoicePnBridge;
44
+
45
+ /**
46
+ * Enhanced VoicePnBridge with call control and event handling capabilities
47
+ */
48
+ export class VoicePnBridge {
49
+ /**
50
+ * Get any pending push notification action from native side
51
+ */
52
+ static async getPendingPushAction(): Promise<{ action?: string; metadata?: string }> {
53
+ try {
54
+ const result = await NativeBridge.getPendingPushAction();
55
+ return {
56
+ action: result?.action || undefined,
57
+ metadata: result?.metadata || undefined,
58
+ };
59
+ } catch (error) {
60
+ console.error('VoicePnBridge: Error getting pending push action:', error);
61
+ return {};
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Set a pending push notification action to native side
67
+ */
68
+ static async setPendingPushAction(action: string, metadata: string): Promise<boolean> {
69
+ try {
70
+ return await NativeBridge.setPendingPushAction(action, metadata);
71
+ } catch (error) {
72
+ console.error('VoicePnBridge: Error setting pending push action:', error);
73
+ return false;
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Get any pending call action from native side (reliable polling pattern)
79
+ */
80
+ static async getPendingCallAction(): Promise<{
81
+ action?: string;
82
+ callId?: string;
83
+ timestamp?: number;
84
+ }> {
85
+ try {
86
+ const result = await NativeBridge.getPendingCallAction();
87
+ return {
88
+ action: result?.action || undefined,
89
+ callId: result?.callId || undefined,
90
+ timestamp: result?.timestamp || undefined,
91
+ };
92
+ } catch (error) {
93
+ console.error('VoicePnBridge: Error getting pending call action:', error);
94
+ return {};
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Clear any pending call action
100
+ */
101
+ static async clearPendingCallAction(): Promise<boolean> {
102
+ try {
103
+ return await NativeBridge.clearPendingCallAction();
104
+ } catch (error) {
105
+ console.error('VoicePnBridge: Error clearing pending call action:', error);
106
+ return false;
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Clear any pending push notification action
112
+ */
113
+ static async clearPendingPushAction(): Promise<boolean> {
114
+ try {
115
+ return await NativeBridge.clearPendingPushAction();
116
+ } catch (error) {
117
+ console.error('VoicePnBridge: Error clearing pending push action:', error);
118
+ return false;
119
+ }
120
+ }
121
+
122
+ /**
123
+ * React Native → Android: End/hang up the current call
124
+ * This will hide the ongoing call notification and notify the native side
125
+ */
126
+ static async endCall(callId?: string): Promise<boolean> {
127
+ try {
128
+ return await NativeBridge.endCall(callId || null);
129
+ } catch (error) {
130
+ console.error('VoicePnBridge: Error ending call:', error);
131
+ return false;
132
+ }
133
+ }
134
+
135
+ /**
136
+ * React Native → Android: Show ongoing call notification to keep app alive
137
+ * Should be called when a call becomes active to prevent background termination
138
+ */
139
+ static async showOngoingCallNotification(
140
+ callerName?: string,
141
+ callerNumber?: string,
142
+ callId?: string
143
+ ): Promise<boolean> {
144
+ try {
145
+ return await NativeBridge.showOngoingCallNotification(
146
+ callerName || null,
147
+ callerNumber || null,
148
+ callId || null
149
+ );
150
+ } catch (error) {
151
+ console.error('VoicePnBridge: Error showing ongoing call notification:', error);
152
+ return false;
153
+ }
154
+ }
155
+
156
+ /**
157
+ * React Native → Android: Hide ongoing call notification
158
+ * Should be called when a call ends to clean up notifications
159
+ */
160
+ static async hideOngoingCallNotification(): Promise<boolean> {
161
+ try {
162
+ return await NativeBridge.hideOngoingCallNotification();
163
+ } catch (error) {
164
+ console.error('VoicePnBridge: Error hiding ongoing call notification:', error);
165
+ return false;
166
+ }
167
+ }
168
+
169
+ /**
170
+ * React Native → Android: Hide incoming call notification
171
+ * Useful for dismissing notifications when call is answered/rejected in app
172
+ */
173
+ static async hideIncomingCallNotification(): Promise<boolean> {
174
+ try {
175
+ return await NativeBridge.hideIncomingCallNotification();
176
+ } catch (error) {
177
+ console.error('VoicePnBridge: Error hiding incoming call notification:', error);
178
+ return false;
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Get VoIP token from native storage
184
+ */
185
+ static async getVoipToken(): Promise<string | null> {
186
+ try {
187
+ return await NativeBridge.getVoipToken();
188
+ } catch (error) {
189
+ console.error('VoicePnBridge: Error getting VoIP token:', error);
190
+ return null;
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Get pending VoIP push from native storage
196
+ */
197
+ static async getPendingVoipPush(): Promise<string | null> {
198
+ try {
199
+ return await NativeBridge.getPendingVoipPush();
200
+ } catch (error) {
201
+ console.error('VoicePnBridge: Error getting pending VoIP push:', error);
202
+ return null;
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Clear pending VoIP push from native storage
208
+ */
209
+ static async clearPendingVoipPush(): Promise<boolean> {
210
+ try {
211
+ return await NativeBridge.clearPendingVoipPush();
212
+ } catch (error) {
213
+ console.error('VoicePnBridge: Error clearing pending VoIP push:', error);
214
+ return false;
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Get pending VoIP action from native storage
220
+ */
221
+ static async getPendingVoipAction(): Promise<string | null> {
222
+ try {
223
+ return await NativeBridge.getPendingVoipAction();
224
+ } catch (error) {
225
+ console.error('VoicePnBridge: Error getting pending VoIP action:', error);
226
+ return null;
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Clear pending VoIP action from native storage
232
+ */
233
+ static async clearPendingVoipAction(): Promise<boolean> {
234
+ try {
235
+ return await NativeBridge.clearPendingVoipAction();
236
+ } catch (error) {
237
+ console.error('VoicePnBridge: Error clearing pending VoIP action:', error);
238
+ return false;
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Android → React Native: Listen for immediate call action events from notification buttons
244
+ * Use this for active calls where immediate response is needed (e.g., ending ongoing calls)
245
+ */
246
+ static addCallActionListener(listener: (event: CallActionEvent) => void): EmitterSubscription {
247
+ return DeviceEventEmitter.addListener('TelnyxCallAction', listener);
248
+ }
249
+
250
+ /**
251
+ * Remove call action listener
252
+ */
253
+ static removeCallActionListener(subscription: EmitterSubscription): void {
254
+ subscription.remove();
255
+ }
256
+
257
+ /**
258
+ * Remove all call action listeners
259
+ */
260
+ static removeAllCallActionListeners(): void {
261
+ DeviceEventEmitter.removeAllListeners('TelnyxCallAction');
262
+ }
263
+ }
264
+
265
+ // Export the native bridge for direct access if needed
266
+ export { NativeBridge as VoicePnBridgeNative };
@@ -1,98 +1,105 @@
1
- /**
2
- * Represents the state of a call in the Telnyx system.
3
- *
4
- * This enum provides a simplified view of call states, abstracting away
5
- * the complexity of the underlying SIP call states.
6
- */
7
- export enum TelnyxCallState {
8
- /** Call is being initiated (outgoing) or received (incoming) */
9
- RINGING = 'RINGING',
10
-
11
- /** Call is connecting after being answered (usually from push notification) */
12
- CONNECTING = 'CONNECTING',
13
-
14
- /** Call has been answered and media is flowing */
15
- ACTIVE = 'ACTIVE',
16
-
17
- /** Call is on hold */
18
- HELD = 'HELD',
19
-
20
- /** Call has ended normally */
21
- ENDED = 'ENDED',
22
-
23
- /** Call failed to connect or was rejected */
24
- FAILED = 'FAILED',
25
- }
26
-
27
- /**
28
- * Type guard to check if a value is a valid TelnyxCallState
29
- */
30
- export function isTelnyxCallState(value: any): value is TelnyxCallState {
31
- return Object.values(TelnyxCallState).includes(value);
32
- }
33
-
34
- /**
35
- * Helper functions to determine what actions are available in each state
36
- */
37
- export const CallStateHelpers = {
38
- /**
39
- * Can the call be answered in this state?
40
- */
41
- canAnswer(state: TelnyxCallState): boolean {
42
- return state === TelnyxCallState.RINGING;
43
- },
44
-
45
- /**
46
- * Can the call be hung up in this state?
47
- */
48
- canHangup(state: TelnyxCallState): boolean {
49
- return (
50
- state === TelnyxCallState.RINGING ||
51
- state === TelnyxCallState.CONNECTING ||
52
- state === TelnyxCallState.ACTIVE ||
53
- state === TelnyxCallState.HELD
54
- );
55
- },
56
-
57
- /**
58
- * Can the call be put on hold in this state?
59
- */
60
- canHold(state: TelnyxCallState): boolean {
61
- return state === TelnyxCallState.ACTIVE;
62
- },
63
-
64
- /**
65
- * Can the call be resumed from hold in this state?
66
- */
67
- canResume(state: TelnyxCallState): boolean {
68
- return state === TelnyxCallState.HELD;
69
- },
70
-
71
- /**
72
- * Can the call be muted/unmuted in this state?
73
- */
74
- canToggleMute(state: TelnyxCallState): boolean {
75
- return state === TelnyxCallState.ACTIVE || state === TelnyxCallState.HELD;
76
- },
77
-
78
- /**
79
- * Is the call in a terminated state?
80
- */
81
- isTerminated(state: TelnyxCallState): boolean {
82
- return state === TelnyxCallState.ENDED || state === TelnyxCallState.FAILED;
83
- },
84
-
85
- /**
86
- * Is the call in an active state (can have media)?
87
- */
88
- isActive(state: TelnyxCallState): boolean {
89
- return state === TelnyxCallState.ACTIVE || state === TelnyxCallState.HELD;
90
- },
91
-
92
- /**
93
- * Is the call in a connecting state (answered but not yet active)?
94
- */
95
- isConnecting(state: TelnyxCallState): boolean {
96
- return state === TelnyxCallState.CONNECTING;
97
- },
98
- };
1
+ /**
2
+ * Represents the state of a call in the Telnyx system.
3
+ *
4
+ * This enum provides a simplified view of call states, abstracting away
5
+ * the complexity of the underlying SIP call states.
6
+ */
7
+ export enum TelnyxCallState {
8
+ /** Call is being initiated (outgoing) or received (incoming) */
9
+ RINGING = 'RINGING',
10
+
11
+ /** Call is connecting after being answered (usually from push notification) */
12
+ CONNECTING = 'CONNECTING',
13
+
14
+ /** Call has been answered and media is flowing */
15
+ ACTIVE = 'ACTIVE',
16
+
17
+ /** Call is on hold */
18
+ HELD = 'HELD',
19
+
20
+ /** Call has ended normally */
21
+ ENDED = 'ENDED',
22
+
23
+ /** Call failed to connect or was rejected */
24
+ FAILED = 'FAILED',
25
+
26
+ /** Call was dropped due to network issues */
27
+ DROPPED = 'DROPPED',
28
+ }
29
+
30
+ /**
31
+ * Type guard to check if a value is a valid TelnyxCallState
32
+ */
33
+ export function isTelnyxCallState(value: any): value is TelnyxCallState {
34
+ return Object.values(TelnyxCallState).includes(value);
35
+ }
36
+
37
+ /**
38
+ * Helper functions to determine what actions are available in each state
39
+ */
40
+ export const CallStateHelpers = {
41
+ /**
42
+ * Can the call be answered in this state?
43
+ */
44
+ canAnswer(state: TelnyxCallState): boolean {
45
+ return state === TelnyxCallState.RINGING;
46
+ },
47
+
48
+ /**
49
+ * Can the call be hung up in this state?
50
+ */
51
+ canHangup(state: TelnyxCallState): boolean {
52
+ return (
53
+ state === TelnyxCallState.RINGING ||
54
+ state === TelnyxCallState.CONNECTING ||
55
+ state === TelnyxCallState.ACTIVE ||
56
+ state === TelnyxCallState.HELD
57
+ );
58
+ },
59
+
60
+ /**
61
+ * Can the call be put on hold in this state?
62
+ */
63
+ canHold(state: TelnyxCallState): boolean {
64
+ return state === TelnyxCallState.ACTIVE;
65
+ },
66
+
67
+ /**
68
+ * Can the call be resumed from hold in this state?
69
+ */
70
+ canResume(state: TelnyxCallState): boolean {
71
+ return state === TelnyxCallState.HELD;
72
+ },
73
+
74
+ /**
75
+ * Can the call be muted/unmuted in this state?
76
+ */
77
+ canToggleMute(state: TelnyxCallState): boolean {
78
+ return state === TelnyxCallState.ACTIVE || state === TelnyxCallState.HELD;
79
+ },
80
+
81
+ /**
82
+ * Is the call in a terminated state?
83
+ */
84
+ isTerminated(state: TelnyxCallState): boolean {
85
+ return (
86
+ state === TelnyxCallState.ENDED ||
87
+ state === TelnyxCallState.FAILED ||
88
+ state === TelnyxCallState.DROPPED
89
+ );
90
+ },
91
+
92
+ /**
93
+ * Is the call in an active state (can have media)?
94
+ */
95
+ isActive(state: TelnyxCallState): boolean {
96
+ return state === TelnyxCallState.ACTIVE || state === TelnyxCallState.HELD;
97
+ },
98
+
99
+ /**
100
+ * Is the call in a connecting state (answered but not yet active)?
101
+ */
102
+ isConnecting(state: TelnyxCallState): boolean {
103
+ return state === TelnyxCallState.CONNECTING;
104
+ },
105
+ };