@revrag-ai/embed-react-native 1.0.5 → 1.0.7

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 (94) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +13 -382
  3. package/android/CMakeLists.txt +15 -0
  4. package/android/build.gradle +77 -25
  5. package/android/cpp-adapter.cpp +8 -0
  6. package/android/generated/java/com/revragai/embedreactnative/NativeEmbedReactNativeSpec.java +37 -0
  7. package/android/generated/jni/CMakeLists.txt +49 -0
  8. package/android/generated/jni/RNEmbedReactNativeSpec-generated.cpp +32 -0
  9. package/android/generated/jni/RNEmbedReactNativeSpec.h +31 -0
  10. package/android/generated/jni/react/renderer/components/RNEmbedReactNativeSpec/RNEmbedReactNativeSpecJSI-generated.cpp +28 -0
  11. package/android/generated/jni/react/renderer/components/RNEmbedReactNativeSpec/RNEmbedReactNativeSpecJSI.h +67 -0
  12. package/android/gradle.properties +5 -5
  13. package/cpp/revrag-ai-embed-react-native.cpp +7 -0
  14. package/cpp/revrag-ai-embed-react-native.h +8 -0
  15. package/ios/EmbedReactNative.h +9 -0
  16. package/ios/{Onwid.mm → EmbedReactNative.mm} +4 -4
  17. package/ios/generated/RNEmbedReactNativeSpec/RNEmbedReactNativeSpec-generated.mm +29 -0
  18. package/ios/generated/RNEmbedReactNativeSpec/RNEmbedReactNativeSpec.h +50 -0
  19. package/ios/generated/RNEmbedReactNativeSpecJSI-generated.cpp +28 -0
  20. package/ios/generated/RNEmbedReactNativeSpecJSI.h +67 -0
  21. package/lib/commonjs/NativeEmbedReactNative.js +9 -0
  22. package/lib/commonjs/api/api.js +256 -0
  23. package/lib/commonjs/api/types/embed.api.types.js +2 -0
  24. package/lib/commonjs/components/Embed/EmbedAudioWave.js +157 -0
  25. package/lib/commonjs/components/Embed/EmbedButton.js +511 -0
  26. package/lib/commonjs/components/Embed/EmbedVoice.js +131 -0
  27. package/lib/commonjs/components/styles/EmbedButton.style.js +248 -0
  28. package/lib/commonjs/events/embed.event.js +74 -0
  29. package/lib/commonjs/hooks/initialize.js +102 -0
  30. package/lib/commonjs/hooks/initialize.livekit.js +20 -0
  31. package/lib/commonjs/hooks/types/initialize.types.js +2 -0
  32. package/lib/commonjs/hooks/types/voiceAgent.types.js +6 -0
  33. package/lib/commonjs/hooks/voiceagent.js +358 -0
  34. package/lib/commonjs/index.js +34 -0
  35. package/lib/commonjs/index.types.js +22 -0
  36. package/lib/commonjs/store/store.key.js +46 -0
  37. package/lib/commonjs/utils/reanimated.helper.js +100 -0
  38. package/lib/module/NativeEmbedReactNative.js +5 -0
  39. package/lib/module/api/api.js +248 -0
  40. package/lib/module/api/types/embed.api.types.js +2 -0
  41. package/lib/module/components/Embed/EmbedAudioWave.js +152 -0
  42. package/lib/module/components/Embed/EmbedButton.js +506 -0
  43. package/lib/module/components/Embed/EmbedVoice.js +127 -0
  44. package/lib/module/components/styles/EmbedButton.style.js +243 -0
  45. package/lib/module/events/embed.event.js +70 -0
  46. package/lib/module/hooks/initialize.js +79 -75
  47. package/lib/module/hooks/{initializelivekit.js → initialize.livekit.js} +7 -4
  48. package/lib/module/hooks/types/initialize.types.js +2 -0
  49. package/lib/module/hooks/types/voiceAgent.types.js +4 -0
  50. package/lib/module/hooks/voiceagent.js +353 -0
  51. package/lib/module/index.js +6 -60
  52. package/lib/module/index.types.js +23 -0
  53. package/lib/module/store/store.key.js +38 -0
  54. package/lib/module/utils/reanimated.helper.js +94 -0
  55. package/lib/typescript/commonjs/package.json +1 -0
  56. package/lib/typescript/module/package.json +1 -0
  57. package/package.json +69 -27
  58. package/react-native.config.js +8 -14
  59. package/revrag-ai-embed-react-native.podspec +41 -0
  60. package/Onwid.podspec +0 -20
  61. package/ios/Onwid.h +0 -5
  62. package/lib/index.d.ts +0 -77
  63. package/lib/module/Event/onwid.js +0 -74
  64. package/lib/module/NativeOnwid.js +0 -4
  65. package/lib/module/component/OnwidButton.js +0 -366
  66. package/lib/module/component/audiowave.js +0 -137
  67. package/lib/module/component/voice.js +0 -103
  68. package/lib/module/hooks/initialize.types.js +0 -2
  69. package/lib/module/hooks/voiceAgent.js +0 -334
  70. package/lib/module/hooks/voiceAgent.types.js +0 -2
  71. package/lib/module/onwidApi/api.js +0 -184
  72. package/lib/module/onwidApi/api.types.js +0 -2
  73. package/lib/module/store.key.js +0 -47
  74. package/lib/module/style/onwidButton.style.js +0 -230
  75. package/lib/module/utils/reanimatedHelpers.js +0 -87
  76. package/lib/module/utils/utils.js +0 -1
  77. package/lib/typescript/Event/onwid.d.ts +0 -13
  78. package/lib/typescript/NativeOnwid.d.ts +0 -6
  79. package/lib/typescript/component/OnwidButton.d.ts +0 -28
  80. package/lib/typescript/component/audiowave.d.ts +0 -6
  81. package/lib/typescript/component/voice.d.ts +0 -15
  82. package/lib/typescript/hooks/initialize.d.ts +0 -2
  83. package/lib/typescript/hooks/initialize.types.d.ts +0 -5
  84. package/lib/typescript/hooks/initializelivekit.d.ts +0 -3
  85. package/lib/typescript/hooks/voiceAgent.d.ts +0 -2
  86. package/lib/typescript/hooks/voiceAgent.types.d.ts +0 -16
  87. package/lib/typescript/index.d.ts +0 -27
  88. package/lib/typescript/onwidApi/api.d.ts +0 -53
  89. package/lib/typescript/onwidApi/api.types.d.ts +0 -21
  90. package/lib/typescript/store.key.d.ts +0 -3
  91. package/lib/typescript/style/onwidButton.style.d.ts +0 -98
  92. package/lib/typescript/utils/reanimatedHelpers.d.ts +0 -29
  93. package/lib/typescript/utils/utils.d.ts +0 -0
  94. package/scripts/verify-setup.js +0 -90
@@ -0,0 +1,248 @@
1
+ "use strict";
2
+
3
+ import { getAgentData, setAgentData } from "../store/store.key.js";
4
+
5
+ /**
6
+ * APIService class that ensures proper initialization before API calls
7
+ */
8
+ export class APIService {
9
+ static instance = null;
10
+ apiBaseUrl = null;
11
+ isInitialized = false;
12
+ constructor() {}
13
+
14
+ /**
15
+ * Get singleton instance of APIService
16
+ */
17
+ static getInstance() {
18
+ if (!APIService.instance) {
19
+ APIService.instance = new APIService();
20
+ }
21
+ return APIService.instance;
22
+ }
23
+
24
+ /**
25
+ * Initialize the API service with the base URL
26
+ */
27
+ async initialize() {
28
+ if (this.isInitialized && this.apiBaseUrl) {
29
+ return; // Already initialized
30
+ }
31
+ const AgentData = await getAgentData();
32
+ console.log('AgentData', AgentData);
33
+ if (AgentData?.onwidUrl) {
34
+ this.apiBaseUrl = AgentData.onwidUrl;
35
+ this.isInitialized = true;
36
+ console.log('API_BASE_URL initialized:', this.apiBaseUrl);
37
+ } else {
38
+ throw new Error('API base URL not found in keychain');
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Ensure the service is initialized before making API calls
44
+ */
45
+ async ensureInitialized() {
46
+ if (!this.isInitialized || !this.apiBaseUrl) {
47
+ await this.initialize();
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Get headers with stored API key
53
+ */
54
+ async getHeaders() {
55
+ const AgentData = await getAgentData();
56
+ if (!AgentData?.apiKey) {
57
+ throw new Error('API key not found in keychain');
58
+ }
59
+ return {
60
+ 'Content-Type': 'application/json',
61
+ 'Authorization': `Bearer ${AgentData.apiKey}`,
62
+ 'X-Revrag-Embedded-Key': AgentData.apiKey
63
+ };
64
+ }
65
+
66
+ /**
67
+ * Register a new user/device on initialization
68
+ * @returns Promise with registration response
69
+ */
70
+ async registerOnInitialize() {
71
+ try {
72
+ await this.ensureInitialized();
73
+ console.log('registerOnInitialize ApiData', this.apiBaseUrl);
74
+ const headers = await this.getHeaders();
75
+ const response = await fetch(`${this.apiBaseUrl}/embedded-agent/initialize`, {
76
+ method: 'GET',
77
+ headers: headers
78
+ });
79
+ const data = await response.json();
80
+ console.log('dat config data after register', data);
81
+ await setAgentData(data, '@config_data');
82
+ if (!response.ok) {
83
+ console.log('registerOnInitialize error', data.error);
84
+ throw new Error(data.error || 'Registration failed');
85
+ }
86
+ return {
87
+ success: true,
88
+ data: data
89
+ };
90
+ } catch (error) {
91
+ console.log('registerOnInitialize error', error);
92
+
93
+ // Enhanced error handling for common iOS network issues
94
+ let errorMessage = 'Unknown error occurred';
95
+ if (error instanceof Error) {
96
+ errorMessage = error.message;
97
+
98
+ // iOS ATS related errors
99
+ if (error.message.includes('The resource could not be loaded') || error.message.includes('App Transport Security')) {
100
+ errorMessage = `Network request blocked by iOS App Transport Security. ` + `Please configure ATS exceptions in Info.plist for HTTP endpoints, ` + `or use HTTPS instead. Error: ${error.message}`;
101
+ }
102
+
103
+ // Network connectivity errors
104
+ if (error.message.includes('Network request failed') || error.message.includes('Failed to fetch')) {
105
+ errorMessage = `Network request failed. Please check your internet connection ` + `and ensure the API endpoint (${this.apiBaseUrl}) is accessible. ` + `Error: ${error.message}`;
106
+ }
107
+
108
+ // Timeout errors
109
+ if (error.message.includes('timeout')) {
110
+ errorMessage = `Request timeout. The API server may be slow to respond or unreachable. ` + `Error: ${error.message}`;
111
+ }
112
+ }
113
+ return {
114
+ success: false,
115
+ error: errorMessage
116
+ };
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Update user data
122
+ * @param params Update parameters including userId and data to update
123
+ * @returns Promise with update response
124
+ */
125
+ async updateUserData(params) {
126
+ try {
127
+ await this.ensureInitialized();
128
+ console.log('params', params, `${this.apiBaseUrl}/embedded-agent/user-context/update?app_user_id=${params.data.app_user_id}`);
129
+ console.log('updateUserData');
130
+ const headers = await this.getHeaders();
131
+ const response = await fetch(`${this.apiBaseUrl}/embedded-agent/user-context/update?app_user_id=${params.data.app_user_id}`, {
132
+ method: 'PUT',
133
+ headers,
134
+ body: JSON.stringify({
135
+ [params.eventKey]: params.data
136
+ })
137
+ });
138
+ const data = await response.json();
139
+ console.log('data after update', data);
140
+ if (!response.ok) {
141
+ throw new Error(data.error || 'Update failed');
142
+ }
143
+ return {
144
+ success: true
145
+ };
146
+ } catch (error) {
147
+ console.log('updateUserData error', error);
148
+
149
+ // Enhanced error handling for common iOS network issues
150
+ let errorMessage = 'Unknown error occurred';
151
+ if (error instanceof Error) {
152
+ errorMessage = error.message;
153
+
154
+ // iOS ATS related errors
155
+ if (error.message.includes('The resource could not be loaded') || error.message.includes('App Transport Security')) {
156
+ errorMessage = `Network request blocked by iOS App Transport Security. ` + `Please configure ATS exceptions in Info.plist for HTTP endpoints, ` + `or use HTTPS instead. Error: ${error.message}`;
157
+ }
158
+
159
+ // Network connectivity errors
160
+ if (error.message.includes('Network request failed') || error.message.includes('Failed to fetch')) {
161
+ errorMessage = `Network request failed. Please check your internet connection ` + `and ensure the API endpoint (${this.apiBaseUrl}) is accessible. ` + `Error: ${error.message}`;
162
+ }
163
+
164
+ // Timeout errors
165
+ if (error.message.includes('timeout')) {
166
+ errorMessage = `Request timeout. The API server may be slow to respond or unreachable. ` + `Error: ${error.message}`;
167
+ }
168
+ }
169
+ return {
170
+ success: false,
171
+ error: errorMessage
172
+ };
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Get token details for a user
178
+ * @param params Parameters including app_user_id and call_type
179
+ * @returns Promise with token details
180
+ */
181
+ async getTokenDetails(params) {
182
+ try {
183
+ await this.ensureInitialized();
184
+ const headers = await this.getHeaders();
185
+ console.log('params', this.apiBaseUrl, params, headers, `${this.apiBaseUrl}/embedded-agent/token`);
186
+ const response = await fetch(`${this.apiBaseUrl}/embedded-agent/token`, {
187
+ method: 'POST',
188
+ headers,
189
+ body: JSON.stringify(params)
190
+ });
191
+ const data = await response.json();
192
+ console.log('data', data);
193
+ if (!response.ok) {
194
+ throw new Error(data.error || 'Failed to get token details');
195
+ }
196
+ return {
197
+ success: true,
198
+ data: data
199
+ };
200
+ } catch (error) {
201
+ console.log('getTokenDetails error', error);
202
+
203
+ // Enhanced error handling for common iOS network issues
204
+ let errorMessage = 'Unknown error occurred';
205
+ if (error instanceof Error) {
206
+ errorMessage = error.message;
207
+
208
+ // iOS ATS related errors
209
+ if (error.message.includes('The resource could not be loaded') || error.message.includes('App Transport Security')) {
210
+ errorMessage = `Network request blocked by iOS App Transport Security. ` + `Please configure ATS exceptions in Info.plist for HTTP endpoints, ` + `or use HTTPS instead. Error: ${error.message}`;
211
+ }
212
+
213
+ // Network connectivity errors
214
+ if (error.message.includes('Network request failed') || error.message.includes('Failed to fetch')) {
215
+ errorMessage = `Network request failed. Please check your internet connection ` + `and ensure the API endpoint (${this.apiBaseUrl}) is accessible. ` + `Error: ${error.message}`;
216
+ }
217
+
218
+ // Timeout errors
219
+ if (error.message.includes('timeout')) {
220
+ errorMessage = `Request timeout. The API server may be slow to respond or unreachable. ` + `Error: ${error.message}`;
221
+ }
222
+ }
223
+ return {
224
+ success: false,
225
+ error: errorMessage
226
+ };
227
+ }
228
+ }
229
+ }
230
+
231
+ // Export convenience functions for backward compatibility
232
+ export const initializeApi = async () => {
233
+ const apiService = APIService.getInstance();
234
+ await apiService.initialize();
235
+ };
236
+ export const registerOnInitialize = async () => {
237
+ const apiService = APIService.getInstance();
238
+ return await apiService.registerOnInitialize();
239
+ };
240
+ export const updateUserData = async params => {
241
+ const apiService = APIService.getInstance();
242
+ return await apiService.updateUserData(params);
243
+ };
244
+ export const getTokenDetails = async params => {
245
+ const apiService = APIService.getInstance();
246
+ return await apiService.getTokenDetails(params);
247
+ };
248
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=embed.api.types.js.map
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+
3
+ import { useEffect, useRef, useState } from 'react';
4
+ import { View, Animated } from 'react-native';
5
+ import { jsx as _jsx } from "react/jsx-runtime";
6
+ // React Native compatible waveform simulator
7
+ const useReactNativeAudioWaveform = roomRef => {
8
+ const [isAudioActive, setIsAudioActive] = useState(false);
9
+ const intervalRef = useRef(null);
10
+ const [currentHeights, setCurrentHeights] = useState(Array(10).fill(0));
11
+
12
+ // Create animated values for each bar
13
+ const barCount = 10;
14
+ const animatedBars = useRef(Array(barCount).fill(0).map(() => new Animated.Value(0))).current;
15
+ useEffect(() => {
16
+ // Check if there's an active room connection AND if agent is talking
17
+ const checkAudioActivity = () => {
18
+ const room = roomRef.current;
19
+ if (room?.state !== 'connected') {
20
+ setIsAudioActive(false);
21
+ return;
22
+ }
23
+
24
+ // Check if any remote participant is currently speaking
25
+ let isAgentSpeaking = false;
26
+
27
+ // Loop through all remote participants
28
+ room.remoteParticipants.forEach(participant => {
29
+ const audioTrackPublications = Array.from(participant.getTrackPublications().values());
30
+ const remoteAudioTrack = audioTrackPublications.find(pub => pub.track?.kind === 'audio');
31
+
32
+ // Check if this participant has audio track, is not muted, and is actively speaking
33
+ if (remoteAudioTrack?.track && !remoteAudioTrack?.isMuted) {
34
+ // Check audio level to detect actual speech (optional but more accurate)
35
+ const audioLevel = participant.audioLevel || 0;
36
+ if (audioLevel > 0.05) {
37
+ // Threshold for detecting speech
38
+ isAgentSpeaking = true;
39
+ }
40
+ }
41
+ });
42
+ setIsAudioActive(isAgentSpeaking);
43
+ };
44
+
45
+ // Initial check
46
+ checkAudioActivity();
47
+
48
+ // Set up periodic checking for room state changes
49
+ intervalRef.current = setInterval(checkAudioActivity, 500);
50
+
51
+ // Clean up on unmount
52
+ return () => {
53
+ if (intervalRef.current) {
54
+ clearInterval(intervalRef.current);
55
+ intervalRef.current = null;
56
+ }
57
+ setIsAudioActive(false);
58
+ };
59
+ }, [roomRef]);
60
+
61
+ // Continuous smooth animation
62
+ useEffect(() => {
63
+ const animateWaveform = () => {
64
+ // Generate smooth waveform data - stop animation completely when not active
65
+ const targetHeights = isAudioActive ? Array(barCount).fill(0).map((_, index) => {
66
+ const timeOffset = Date.now() / 800 + index * 0.3;
67
+ const baseHeight = 0.5;
68
+ const amplitude = 0.5;
69
+ const height = baseHeight + amplitude * Math.abs(Math.sin(timeOffset));
70
+ return Math.max(0.1, Math.min(1.0, height));
71
+ }) : Array(barCount).fill(0); // Completely freeze animation when mic is muted
72
+
73
+ // Update current heights for conditional logic
74
+ setCurrentHeights(targetHeights);
75
+ const animations = animatedBars.map((animatedValue, index) => {
76
+ const targetHeight = targetHeights[index] || 0;
77
+ return Animated.timing(animatedValue, {
78
+ toValue: targetHeight,
79
+ duration: isAudioActive ? 400 : 600,
80
+ // Slower fade out when going inactive
81
+ useNativeDriver: false
82
+ });
83
+ });
84
+ Animated.parallel(animations).start();
85
+ };
86
+
87
+ // Start animation immediately and repeat
88
+ animateWaveform();
89
+ const animationInterval = setInterval(animateWaveform, 300);
90
+ return () => {
91
+ clearInterval(animationInterval);
92
+ };
93
+ }, [isAudioActive, animatedBars]);
94
+ return {
95
+ animatedBars,
96
+ currentHeights,
97
+ isActive: isAudioActive
98
+ };
99
+ };
100
+ export const WaveformVisualizer = ({
101
+ roomRef
102
+ }) => {
103
+ const {
104
+ animatedBars,
105
+ currentHeights
106
+ } = useReactNativeAudioWaveform(roomRef);
107
+ console.log('animatedBars', animatedBars);
108
+ return /*#__PURE__*/_jsx(View, {
109
+ style: {
110
+ flexDirection: 'row',
111
+ alignItems: 'center',
112
+ height: '100%',
113
+ alignSelf: 'center',
114
+ // width: '100%',
115
+ // flex: 1,
116
+ justifyContent: 'center',
117
+ // position: 'absolute',
118
+ zIndex: 1000
119
+ },
120
+ children: animatedBars.map((animatedHeight, idx) => {
121
+ // Use the tracked height values instead of trying to access animated value directly
122
+ const currentHeightValue = currentHeights[idx] || 0.1;
123
+
124
+ // Apply conditional logic based on height
125
+ let conditionalValue;
126
+ if (currentHeightValue > 0.7) {
127
+ conditionalValue = 1;
128
+ } else if (currentHeightValue >= 0.4 && currentHeightValue <= 0.5) {
129
+ conditionalValue = 5;
130
+ } else {
131
+ conditionalValue = 1;
132
+ }
133
+
134
+ // You can use conditionalValue for width, color, or other properties
135
+ return /*#__PURE__*/_jsx(Animated.View, {
136
+ style: {
137
+ width: conditionalValue === 10 ? 4 : 4,
138
+ borderRadius: 100,
139
+ // Example: wider bars for value 5
140
+ height: animatedHeight.interpolate({
141
+ inputRange: [0, 1],
142
+ outputRange: [0, 25]
143
+ }),
144
+ alignSelf: 'center',
145
+ backgroundColor: idx <= 1 || idx >= 8 ? 'rgba(255, 255, 255, 0.5)' : 'white',
146
+ margin: 1.5
147
+ }
148
+ }, idx);
149
+ })
150
+ });
151
+ };
152
+ //# sourceMappingURL=EmbedAudioWave.js.map