@robylon/react-native-sdk 2.0.32-staging.4 → 2.1.0

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 (63) hide show
  1. package/android/build.gradle +35 -0
  2. package/ios/RobylonDownloadModule.h +5 -0
  3. package/ios/RobylonDownloadModule.m +124 -0
  4. package/lib/commonjs/Chatbotsdk.js +4 -4
  5. package/lib/commonjs/Chatbotsdk.js.map +1 -1
  6. package/lib/commonjs/config.js +1 -1
  7. package/lib/commonjs/config.js.map +1 -1
  8. package/lib/commonjs/constants.js +1 -1
  9. package/lib/commonjs/constants.js.map +1 -1
  10. package/lib/commonjs/utils/fileDownload.js +1 -1
  11. package/lib/commonjs/utils/fileDownload.js.map +1 -1
  12. package/lib/commonjs/versions/version.staging.js +1 -1
  13. package/lib/module/Chatbotsdk.js +4 -4
  14. package/lib/module/Chatbotsdk.js.map +1 -1
  15. package/lib/module/config.js +1 -1
  16. package/lib/module/config.js.map +1 -1
  17. package/lib/module/constants.js +1 -1
  18. package/lib/module/constants.js.map +1 -1
  19. package/lib/module/utils/fileDownload.js +1 -1
  20. package/lib/module/utils/fileDownload.js.map +1 -1
  21. package/lib/module/versions/version.staging.js +1 -1
  22. package/lib/typescript/Chatbotsdk.d.ts.map +1 -1
  23. package/lib/typescript/utils/fileDownload.d.ts +3 -2
  24. package/lib/typescript/utils/fileDownload.d.ts.map +1 -1
  25. package/lib/typescript/versions/version.staging.d.ts +1 -1
  26. package/package.json +3 -3
  27. package/robylon-react-native-sdk.podspec +18 -0
  28. package/src/Chatbotsdk.tsx +0 -979
  29. package/src/FloatingButton/launchers/ImageLauncher.tsx +0 -75
  30. package/src/FloatingButton/launchers/TextLauncher.tsx +0 -84
  31. package/src/FloatingButton/launchers/TextualImageLauncher.tsx +0 -133
  32. package/src/FloatingButton.tsx +0 -97
  33. package/src/LoadingIndicator.tsx +0 -11
  34. package/src/Toast.tsx +0 -65
  35. package/src/components/DebugButton.tsx +0 -46
  36. package/src/components/ErrorBoundary.tsx +0 -38
  37. package/src/config.ts +0 -4
  38. package/src/constants/errorConstants.ts +0 -21
  39. package/src/constants/fontStyles.ts +0 -3
  40. package/src/constants.ts +0 -5
  41. package/src/global.d.ts +0 -11
  42. package/src/hooks/useChatbotEvents.ts +0 -93
  43. package/src/index.tsx +0 -10
  44. package/src/openChatbot.ts +0 -11
  45. package/src/openChatbot.tsx +0 -0
  46. package/src/services/ErrorTrackingService.ts +0 -217
  47. package/src/types/events.ts +0 -28
  48. package/src/types/react-native-flipper-performance-plugin.d.ts +0 -3
  49. package/src/types/react-native-globals.d.ts +0 -10
  50. package/src/utils/animations.ts +0 -120
  51. package/src/utils/colorUtils.ts +0 -35
  52. package/src/utils/cookieUtils.ts +0 -7
  53. package/src/utils/debugConfig.ts +0 -56
  54. package/src/utils/debugMenu.ts +0 -14
  55. package/src/utils/errorHandler.ts +0 -58
  56. package/src/utils/fileDownload.ts +0 -70
  57. package/src/utils/logger.ts +0 -14
  58. package/src/utils/systemInfo.ts +0 -110
  59. package/src/utils/webViewStorage.ts +0 -62
  60. package/src/version.ts +0 -2
  61. package/src/versions/version.dev.ts +0 -2
  62. package/src/versions/version.production.ts +0 -2
  63. package/src/versions/version.staging.ts +0 -2
package/src/index.tsx DELETED
@@ -1,10 +0,0 @@
1
- export { default as Chatbot } from "./Chatbotsdk";
2
- export { openChatbot } from "./openChatbot";
3
- export {
4
- errorTracker,
5
- ErrorTrackingService,
6
- } from "./services/ErrorTrackingService";
7
- export * from "./constants/errorConstants";
8
- export * from "./types/events";
9
-
10
- export type { ChatbotProps, ChatbotRef } from "./Chatbotsdk";
@@ -1,11 +0,0 @@
1
- import { Linking } from "react-native";
2
- import { BASE_CHATBOT_URL } from "./constants";
3
-
4
- export const openChatbot = (
5
- chatbotId: string,
6
- additionalParams: Record<string, string> = {}
7
- ): void => {
8
- const params = new URLSearchParams({ id: chatbotId, ...additionalParams });
9
- const url = `${BASE_CHATBOT_URL}?${params.toString()}`;
10
- Linking.openURL(url);
11
- };
File without changes
@@ -1,217 +0,0 @@
1
- import { getSystemInfo } from "../utils/systemInfo";
2
- import { logger } from "../utils/logger";
3
- import { API_URL } from "../constants";
4
- import { Platform } from "react-native";
5
-
6
- export enum EventType {
7
- ERROR = "ERROR",
8
- INFO = "INFO",
9
- }
10
-
11
- export interface ErrorEvent {
12
- message: string;
13
- stack?: string;
14
- componentName?: string | null | undefined;
15
- additionalInfo?: Record<string, any>;
16
- timestamp: number;
17
- }
18
-
19
- export interface LogPayload {
20
- org_id: string;
21
- event_data: ErrorEvent;
22
- metadata: Record<string, any>;
23
- event_type: EventType;
24
- user_id?: string | number | null;
25
- }
26
-
27
- export class ErrorTrackingService {
28
- private static instance: ErrorTrackingService;
29
- private apiKey: string = "";
30
- private userId: string | number | null | undefined = null;
31
- private preInitQueue: Array<{
32
- error: Error | string;
33
- componentName?: string | null | undefined;
34
- additionalInfo?: Record<string, any>;
35
- }> = [];
36
- private isInitialized = false;
37
-
38
- private constructor() {}
39
-
40
- static getInstance(): ErrorTrackingService {
41
- if (!ErrorTrackingService.instance) {
42
- ErrorTrackingService.instance = new ErrorTrackingService();
43
- }
44
- return ErrorTrackingService.instance;
45
- }
46
-
47
- initialize(apiKey: string, userId: string | number | null = null) {
48
- try {
49
- // Handle pre-init errors
50
- if (this.preInitQueue.length > 0) {
51
- const payload: LogPayload = {
52
- org_id: "UNINITALIZED",
53
- event_data: {
54
- message: `SDK Initialization Failed: Required parameter 'api_key' is ${
55
- apiKey === undefined
56
- ? "undefined"
57
- : apiKey === null
58
- ? "null"
59
- : apiKey === ""
60
- ? "empty string"
61
- : `invalid: ${apiKey}`
62
- }`,
63
- componentName: "ErrorTrackingService",
64
- additionalInfo: {
65
- preInitError: true,
66
- apiKey,
67
- userId,
68
- timestamp: Date.now(),
69
- },
70
- timestamp: Date.now(),
71
- },
72
- metadata: getSystemInfo({ os: Platform.OS, browser: "React Native" }),
73
- event_type: EventType.ERROR,
74
- user_id: userId,
75
- };
76
-
77
- this.sendLog(payload).catch((error) =>
78
- logger.error("Send log error:", error)
79
- );
80
- }
81
-
82
- this.apiKey = apiKey;
83
- this.userId = userId;
84
- this.isInitialized = true;
85
-
86
- this.processPreInitQueue();
87
- } catch (error) {
88
- logger.error("Error during ErrorTrackingService initialization:", error);
89
- this.preInitQueue.push({
90
- error: error instanceof Error ? error : new Error(String(error)),
91
- componentName: "ErrorTrackingService",
92
- additionalInfo: { apiKey, userId },
93
- });
94
- }
95
- }
96
-
97
- private async processPreInitQueue() {
98
- if (!this.preInitQueue.length) return;
99
-
100
- logger.info(
101
- `Processing ${this.preInitQueue.length} pre-initialization errors`
102
- );
103
-
104
- for (const item of this.preInitQueue) {
105
- await this.trackError(item.error, item.componentName, {
106
- ...item.additionalInfo,
107
- preInitError: true,
108
- });
109
- }
110
-
111
- this.preInitQueue = [];
112
- }
113
-
114
- private async sendLog(payload: LogPayload): Promise<void> {
115
- try {
116
- logger.debug("Sending error log:", payload);
117
- const response = await fetch(`${API_URL}/users/sdk/record-logs/`, {
118
- method: "POST",
119
- headers: {
120
- "Content-Type": "application/json",
121
- },
122
- body: JSON.stringify(payload),
123
- });
124
-
125
- if (!response.ok) {
126
- logger.error("Failed to send error log:", await response.text());
127
- }
128
- } catch (error) {
129
- logger.error("Error sending log:", error);
130
- }
131
- }
132
-
133
- async trackError(
134
- error: Error | string,
135
- componentName: string | null | undefined,
136
- additionalInfo?: Record<string, any>
137
- ) {
138
- if (!this.isInitialized) {
139
- const payload: LogPayload = {
140
- org_id: "UNINITALIZED",
141
- event_data: {
142
- message: error instanceof Error ? error.message : error,
143
- stack: error instanceof Error ? error.stack : undefined,
144
- componentName,
145
- additionalInfo: {
146
- ...additionalInfo,
147
- preInitError: true,
148
- timestamp: Date.now(),
149
- },
150
- timestamp: Date.now(),
151
- },
152
- metadata: getSystemInfo({ os: Platform.OS, browser: "React Native" }),
153
- event_type: EventType.ERROR,
154
- user_id: this.userId,
155
- };
156
-
157
- try {
158
- await this.sendLog(payload);
159
- } catch (sendError) {
160
- this.preInitQueue.push({ error, componentName, additionalInfo });
161
- logger.warn("Error tracked before initialization, queuing:", error);
162
- }
163
- return;
164
- }
165
-
166
- const errorEvent: ErrorEvent = {
167
- message: error instanceof Error ? error.message : error,
168
- stack: error instanceof Error ? error.stack : undefined,
169
- componentName,
170
- additionalInfo: {
171
- ...additionalInfo,
172
- timestamp: Date.now(),
173
- },
174
- timestamp: Date.now(),
175
- };
176
-
177
- const payload: LogPayload = {
178
- org_id: this.apiKey || "UNINITALIZED",
179
- event_data: errorEvent,
180
- metadata: getSystemInfo({ os: Platform.OS, browser: "React Native" }),
181
- event_type: EventType.ERROR,
182
- user_id: this.userId,
183
- };
184
-
185
- await this.sendLog(payload);
186
- }
187
-
188
- async trackInfo(
189
- message: string,
190
- componentName: string | null | undefined,
191
- additionalInfo?: Record<string, any>
192
- ) {
193
- if (!this.apiKey) {
194
- logger.error("Error tracking not initialized");
195
- return;
196
- }
197
-
198
- const infoEvent: ErrorEvent = {
199
- message,
200
- componentName,
201
- additionalInfo,
202
- timestamp: Date.now(),
203
- };
204
-
205
- const payload: LogPayload = {
206
- org_id: this.apiKey,
207
- event_data: infoEvent,
208
- metadata: getSystemInfo({ os: Platform.OS, browser: "React Native" }),
209
- event_type: EventType.INFO,
210
- user_id: this.userId,
211
- };
212
-
213
- await this.sendLog(payload);
214
- }
215
- }
216
-
217
- export const errorTracker = ErrorTrackingService.getInstance();
@@ -1,28 +0,0 @@
1
- export enum ChatbotEventType {
2
- CHATBOT_BUTTON_LOADED = "CHATBOT_BUTTON_LOADED",
3
- CHATBOT_BUTTON_CLICKED = "CHATBOT_BUTTON_CLICKED",
4
- CHATBOT_OPENED = "CHATBOT_OPENED",
5
- CHATBOT_CLOSED = "CHATBOT_CLOSED",
6
- CHATBOT_APP_READY = "CHATBOT_APP_READY",
7
- CHATBOT_LOADED = "CHATBOT_LOADED",
8
- CHAT_INITIALIZED = "CHAT_INITIALIZED",
9
- SESSION_REFRESHED = "SESSION_REFRESHED",
10
- CHAT_INITIALIZATION_FAILED = "CHAT_INITIALIZATION_FAILED",
11
- REQUEST_MIC_PERMISSION = "REQUEST_MIC_PERMISSION",
12
- MIC_PERMISSION_GRANTED = "MIC_PERMISSION_GRANTED",
13
- MIC_PERMISSION_DENIED = "MIC_PERMISSION_DENIED",
14
- }
15
-
16
- export enum InternalEventType {
17
- CHAT_MOVED = "CHAT_MOVED",
18
- }
19
-
20
- export type AllEventTypes = ChatbotEventType | InternalEventType;
21
-
22
- export interface ChatbotEvent {
23
- type: ChatbotEventType;
24
- timestamp: number;
25
- data?: any;
26
- }
27
-
28
- export type ChatbotEventHandler = (event: ChatbotEvent) => void;
@@ -1,3 +0,0 @@
1
- declare module "react-native-flipper-performance-plugin" {
2
- export function addPlugin(): void;
3
- }
@@ -1,10 +0,0 @@
1
- declare global {
2
- interface Global {
3
- ErrorUtils: {
4
- setGlobalHandler(callback: (error: Error) => void): void;
5
- getGlobalHandler(): (error: Error, isFatal?: boolean) => void;
6
- };
7
- }
8
- }
9
-
10
- export {};
@@ -1,120 +0,0 @@
1
- import { Animated, Easing } from "react-native";
2
-
3
- // Custom easing function that matches the web version
4
- export const customEasing = Easing.bezier(0.2, 1.27, 0.29, 0.97);
5
-
6
- export const ANIMATION_CONFIG = {
7
- DURATION: {
8
- ENTER: {
9
- TRANSFORM: 200, // 0.2 seconds for enter
10
- OPACITY: 150, // 0.15 seconds for enter
11
- },
12
- EXIT: {
13
- TRANSFORM: 100, // 0.1 seconds for exit (faster)
14
- OPACITY: 80, // 0.08 seconds for exit (faster)
15
- },
16
- },
17
- SCALE: {
18
- BUTTON: {
19
- DEFAULT: 1,
20
- ACTIVE: 0.85,
21
- },
22
- IFRAME: {
23
- HIDDEN: 0.3,
24
- VISIBLE: 1,
25
- },
26
- },
27
- TRANSLATE: {
28
- Y: 40, // translateY value for animations
29
- },
30
- };
31
-
32
- interface AnimatedValues {
33
- scale: Animated.Value;
34
- translateY: Animated.Value;
35
- opacity: Animated.Value;
36
- }
37
-
38
- export const createAnimatedValues = (): AnimatedValues => ({
39
- scale: new Animated.Value(1),
40
- translateY: new Animated.Value(0),
41
- opacity: new Animated.Value(1),
42
- });
43
-
44
- export const animateWebViewOpen = (
45
- animatedValues: AnimatedValues,
46
- callback?: () => void
47
- ) => {
48
- // Reset initial values
49
- animatedValues.scale.setValue(ANIMATION_CONFIG.SCALE.IFRAME.HIDDEN);
50
- animatedValues.translateY.setValue(ANIMATION_CONFIG.TRANSLATE.Y);
51
- animatedValues.opacity.setValue(0);
52
-
53
- Animated.parallel([
54
- // Scale and translate animation
55
- Animated.timing(animatedValues.scale, {
56
- toValue: ANIMATION_CONFIG.SCALE.IFRAME.VISIBLE,
57
- duration: ANIMATION_CONFIG.DURATION.ENTER.TRANSFORM,
58
- easing: customEasing,
59
- useNativeDriver: true,
60
- }),
61
- Animated.timing(animatedValues.translateY, {
62
- toValue: 0,
63
- duration: ANIMATION_CONFIG.DURATION.ENTER.TRANSFORM,
64
- easing: customEasing,
65
- useNativeDriver: true,
66
- }),
67
- // Opacity animation
68
- Animated.timing(animatedValues.opacity, {
69
- toValue: 1,
70
- duration: ANIMATION_CONFIG.DURATION.ENTER.OPACITY,
71
- easing: Easing.ease,
72
- useNativeDriver: true,
73
- }),
74
- ]).start(callback);
75
- };
76
-
77
- export const animateWebViewClose = (
78
- animatedValues: AnimatedValues,
79
- callback?: () => void
80
- ) => {
81
- Animated.parallel([
82
- // Scale and translate animation
83
- Animated.timing(animatedValues.scale, {
84
- toValue: ANIMATION_CONFIG.SCALE.IFRAME.HIDDEN,
85
- duration: ANIMATION_CONFIG.DURATION.EXIT.TRANSFORM,
86
- easing: customEasing,
87
- useNativeDriver: true,
88
- }),
89
- Animated.timing(animatedValues.translateY, {
90
- toValue: ANIMATION_CONFIG.TRANSLATE.Y,
91
- duration: ANIMATION_CONFIG.DURATION.EXIT.TRANSFORM,
92
- easing: customEasing,
93
- useNativeDriver: true,
94
- }),
95
- // Opacity animation
96
- Animated.timing(animatedValues.opacity, {
97
- toValue: 0,
98
- duration: ANIMATION_CONFIG.DURATION.EXIT.OPACITY,
99
- easing: Easing.ease,
100
- useNativeDriver: true,
101
- }),
102
- ]).start(callback);
103
- };
104
-
105
- export const animateButtonScale = (
106
- scale: Animated.Value,
107
- isActive: boolean,
108
- callback?: () => void
109
- ) => {
110
- Animated.timing(scale, {
111
- toValue: isActive
112
- ? ANIMATION_CONFIG.SCALE.BUTTON.ACTIVE
113
- : ANIMATION_CONFIG.SCALE.BUTTON.DEFAULT,
114
- duration: isActive
115
- ? ANIMATION_CONFIG.DURATION.ENTER.TRANSFORM
116
- : ANIMATION_CONFIG.DURATION.EXIT.TRANSFORM,
117
- easing: customEasing,
118
- useNativeDriver: true,
119
- }).start(callback);
120
- };
@@ -1,35 +0,0 @@
1
- export const getBestFontColor = (
2
- backgroundColor: string,
3
- contrastThreshold = 0.5
4
- ): string => {
5
- const whiteShade = "#FFFFFF"; // Light white shade
6
- const blackShade = "#0E0E0F"; // Dark black shade
7
-
8
- // Function to convert hex to RGB
9
- const hexToRgb = (hex: string) => {
10
- const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
11
- hex = hex.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b);
12
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
13
- return result
14
- ? {
15
- r: parseInt(result[1], 16),
16
- g: parseInt(result[2], 16),
17
- b: parseInt(result[3], 16),
18
- }
19
- : { r: 0, g: 0, b: 0 };
20
- };
21
-
22
- // Function to calculate luminance
23
- const luminance = (r: number, g: number, b: number) => {
24
- const a = [r, g, b].map((v) => {
25
- v /= 255;
26
- return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
27
- });
28
- return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
29
- };
30
-
31
- const { r, g, b } = hexToRgb(backgroundColor);
32
- const bgLuminance = luminance(r, g, b);
33
-
34
- return bgLuminance > contrastThreshold ? blackShade : whiteShade;
35
- };
@@ -1,7 +0,0 @@
1
- export const generateUUID = () => {
2
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
3
- const r = (Math.random() * 16) | 0,
4
- v = c === "x" ? r : (r & 0x3) | 0x8;
5
- return v.toString(16);
6
- });
7
- };
@@ -1,56 +0,0 @@
1
- import { Platform } from "react-native";
2
-
3
- declare global {
4
- interface Window {
5
- ReactNativeWebView: any;
6
- }
7
- }
8
-
9
- declare let global: {
10
- XMLHttpRequest: any;
11
- FormData: any;
12
- originalXMLHttpRequest: any;
13
- originalFormData: any;
14
- };
15
-
16
- export const enableNetworkDebug = () => {
17
- if (__DEV__) {
18
- // Enable network request debugging
19
- global.XMLHttpRequest =
20
- global.originalXMLHttpRequest || global.XMLHttpRequest;
21
- global.FormData = global.originalFormData || global.FormData;
22
- }
23
- };
24
-
25
- export const enableWebViewDebug = (webViewRef: any) => {
26
- if (__DEV__ && Platform.OS === "ios") {
27
- // Enable console.log from WebView to show in native debugger
28
- const script = `
29
- window.onerror = function(message, sourcefile, lineno, colno, error) {
30
- window.ReactNativeWebView.postMessage(JSON.stringify({
31
- type: 'ERROR',
32
- data: { message, sourcefile, lineno, colno, error: error?.toString() }
33
- }));
34
- };
35
-
36
- console = new Proxy(console, {
37
- get: function(target, property) {
38
- const origMethod = target[property];
39
- return function(...args) {
40
- const logData = args.map(arg =>
41
- typeof arg === 'object' ? JSON.stringify(arg) : arg
42
- ).join(' ');
43
-
44
- window.ReactNativeWebView.postMessage(JSON.stringify({
45
- type: 'CONSOLE',
46
- level: property,
47
- data: logData
48
- }));
49
- origMethod.apply(target, args);
50
- };
51
- }
52
- });
53
- true;`;
54
- webViewRef.current?.injectJavaScript(script);
55
- }
56
- };
@@ -1,14 +0,0 @@
1
- import { Platform, NativeModules } from "react-native";
2
-
3
- export const openDebugMenu = () => {
4
- if (Platform.OS === "ios") {
5
- NativeModules.DevMenu.show();
6
- }
7
- };
8
-
9
- export const openDebuggerFromApp = () => {
10
- if (Platform.OS === "ios") {
11
- // For iOS
12
- NativeModules.DevSettings.setIsDebuggingRemotely(true);
13
- }
14
- };
@@ -1,58 +0,0 @@
1
- import { logger } from "./logger";
2
- import { ErrorTypes } from "../constants/errorConstants";
3
- import { Platform } from "react-native";
4
- import { errorTracker } from "../services/ErrorTrackingService";
5
-
6
- // Global error handler for uncaught errors and promise rejections
7
- export const setupGlobalErrorHandlers = () => {
8
- if (__DEV__) {
9
- // Handle synchronous errors
10
- const errorHandler = (error: Error, isFatal?: boolean) => {
11
- errorTracker.trackError(error, "GlobalErrorHandler", {
12
- isFatal,
13
- type: ErrorTypes.RUNTIME_ERROR,
14
- platform: Platform.OS,
15
- });
16
- };
17
-
18
- // Handle promise rejections
19
- const rejectionHandler = (event: any) => {
20
- errorTracker.trackError(
21
- event?.reason || new Error("Unknown Promise Error"),
22
- "UnhandledPromiseRejection",
23
- {
24
- type: ErrorTypes.RUNTIME_ERROR,
25
- platform: Platform.OS,
26
- }
27
- );
28
- };
29
-
30
- // Set up handlers
31
- if ((global as any).ErrorUtils) {
32
- const prevHandler = (global as any).ErrorUtils.getGlobalHandler();
33
- (global as any).ErrorUtils.setGlobalHandler(
34
- (error: Error, isFatal?: boolean) => {
35
- errorHandler(error, isFatal);
36
- prevHandler(error, isFatal);
37
- }
38
- );
39
- }
40
-
41
- // Handle promise rejections
42
- const setupPromiseRejectionTracking = () => {
43
- const tracking = require("promise/setimmediate/rejection-tracking");
44
- tracking.enable({
45
- allRejections: true,
46
- onUnhandled: (id: number, error: Error) => {
47
- rejectionHandler({ reason: error });
48
- },
49
- });
50
- };
51
-
52
- try {
53
- setupPromiseRejectionTracking();
54
- } catch (error) {
55
- logger.warn("Promise rejection tracking setup failed:", error);
56
- }
57
- }
58
- };
@@ -1,70 +0,0 @@
1
- /**
2
- * File: src/utils/fileDownload.ts
3
- * Utility functions for handling file downloads
4
- */
5
-
6
- import { Platform, Linking } from "react-native";
7
- import { logger } from "./logger";
8
-
9
- export interface DownloadRequest {
10
- url: string;
11
- filename?: string;
12
- }
13
-
14
- /**
15
- * Downloads a file using the platform's default mechanism
16
- * @param url - The URL of the file to download
17
- * @param filename - Optional filename for the download
18
- */
19
- export const downloadFile = async (
20
- url: string,
21
- filename?: string
22
- ): Promise<void> => {
23
- try {
24
- logger.debug("Initiating file download", { url, filename });
25
-
26
- // Validate URL
27
- if (!url || typeof url !== "string") {
28
- throw new Error("Invalid URL provided for download");
29
- }
30
-
31
- // For React Native, we'll use Linking to open the URL
32
- // This will use the device's default browser/download manager
33
- const supported = await Linking.canOpenURL(url);
34
-
35
- if (!supported) {
36
- throw new Error("Cannot open the provided URL");
37
- }
38
-
39
- await Linking.openURL(url);
40
- logger.debug("File download initiated successfully");
41
- } catch (error) {
42
- logger.error("File download failed", { url, filename, error });
43
- throw error;
44
- }
45
- };
46
-
47
- /**
48
- * Handles download request from WebView post message
49
- * @param downloadRequest - The download request object
50
- */
51
- export const handleDownloadRequest = async (
52
- downloadRequest: DownloadRequest
53
- ): Promise<void> => {
54
- const { url, filename } = downloadRequest;
55
-
56
- if (!url) {
57
- logger.error("Download request missing URL");
58
- return;
59
- }
60
-
61
- try {
62
- await downloadFile(url, filename);
63
- } catch (error) {
64
- logger.error("Failed to handle download request", {
65
- downloadRequest,
66
- error,
67
- });
68
- // Don't re-throw to avoid breaking the WebView message handling
69
- }
70
- };
@@ -1,14 +0,0 @@
1
- export const logger = {
2
- error: (message: string, error?: any) => {
3
- console.error(message, error);
4
- },
5
- info: (message: string, data?: any) => {
6
- console.info(message, data);
7
- },
8
- warn: (message: string, data?: any) => {
9
- console.warn(message, data);
10
- },
11
- debug: (message: string, data?: any) => {
12
- console.log(message, data);
13
- },
14
- };