@uploadista/react-native-core 0.0.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.
@@ -0,0 +1,359 @@
1
+ /**
2
+ * Core types for React Native Uploadista client
3
+ */
4
+
5
+ /**
6
+ * Options for file picker operations
7
+ */
8
+ export interface PickerOptions {
9
+ /** Allowed file types/MIME types */
10
+ allowedTypes?: string[];
11
+ /** Allow multiple selection */
12
+ allowMultiple?: boolean;
13
+ /** Maximum file size in bytes */
14
+ maxSize?: number;
15
+ }
16
+
17
+ /**
18
+ * Options for camera operations
19
+ */
20
+ export interface CameraOptions {
21
+ /** Camera to use: 'front' or 'back' */
22
+ cameraType?: "front" | "back";
23
+ /** Image quality (0-1) */
24
+ quality?: number;
25
+ /** Maximum width for captured image */
26
+ maxWidth?: number;
27
+ /** Maximum height for captured image */
28
+ maxHeight?: number;
29
+ }
30
+
31
+ /**
32
+ * Result from a file pick operation
33
+ */
34
+ export interface FilePickResult {
35
+ /** URI to the file (platform-specific format) */
36
+ uri: string;
37
+ /** File name with extension */
38
+ name: string;
39
+ /** File size in bytes */
40
+ size: number;
41
+ /** MIME type of the file (if available) */
42
+ mimeType?: string;
43
+ /** Local file path (if available) */
44
+ localPath?: string;
45
+ }
46
+
47
+ /**
48
+ * Information about a file
49
+ */
50
+ export interface FileInfo {
51
+ /** URI to the file */
52
+ uri: string;
53
+ /** File name */
54
+ name: string;
55
+ /** File size in bytes */
56
+ size: number;
57
+ /** MIME type (if available) */
58
+ mimeType?: string;
59
+ /** Last modified timestamp */
60
+ modificationTime?: number;
61
+ }
62
+
63
+ /**
64
+ * Interface for file system abstraction layer
65
+ * Provides pluggable access to file system APIs across different RN environments
66
+ */
67
+ export interface FileSystemProvider {
68
+ /**
69
+ * Opens a document picker for selecting files
70
+ * @param options - Configuration for the picker
71
+ * @returns Promise resolving to picked file information
72
+ */
73
+ pickDocument(options?: PickerOptions): Promise<FilePickResult>;
74
+
75
+ /**
76
+ * Opens an image picker for selecting images from gallery
77
+ * @param options - Configuration for the picker
78
+ * @returns Promise resolving to picked image information
79
+ */
80
+ pickImage(options?: PickerOptions): Promise<FilePickResult>;
81
+
82
+ /**
83
+ * Opens a video picker for selecting videos from gallery
84
+ * @param options - Configuration for the picker
85
+ * @returns Promise resolving to picked video information
86
+ */
87
+ pickVideo(options?: PickerOptions): Promise<FilePickResult>;
88
+
89
+ /**
90
+ * Captures a photo using the device camera
91
+ * @param options - Configuration for camera
92
+ * @returns Promise resolving to captured photo information
93
+ */
94
+ pickCamera(options?: CameraOptions): Promise<FilePickResult>;
95
+
96
+ /**
97
+ * Gets a URI for a document that can be read
98
+ * @param filePath - Path to the document
99
+ * @returns Promise resolving to accessible URI
100
+ */
101
+ getDocumentUri(filePath: string): Promise<string>;
102
+
103
+ /**
104
+ * Reads file contents as ArrayBuffer
105
+ * @param uri - URI to read from
106
+ * @returns Promise resolving to file contents as ArrayBuffer
107
+ */
108
+ readFile(uri: string): Promise<ArrayBuffer>;
109
+
110
+ /**
111
+ * Gets information about a file
112
+ * @param uri - URI of the file
113
+ * @returns Promise resolving to file information
114
+ */
115
+ getFileInfo(uri: string): Promise<FileInfo>;
116
+ }
117
+
118
+ /**
119
+ * Configuration for file system provider
120
+ */
121
+ export interface FileSystemProviderConfig {
122
+ /** Type of provider: 'expo' or 'native' */
123
+ type?: "expo" | "native";
124
+ /** Custom provider instance */
125
+ provider?: FileSystemProvider;
126
+ }
127
+
128
+ /**
129
+ * Upload state
130
+ */
131
+ export type UploadState =
132
+ | "idle"
133
+ | "pending"
134
+ | "uploading"
135
+ | "success"
136
+ | "error"
137
+ | "cancelled";
138
+
139
+ /**
140
+ * Upload progress information
141
+ */
142
+ export interface UploadProgress {
143
+ /** Current state of upload */
144
+ state: UploadState;
145
+ /** Progress percentage (0-100) */
146
+ progress: number;
147
+ /** Bytes uploaded */
148
+ uploadedBytes: number;
149
+ /** Total bytes to upload */
150
+ totalBytes: number;
151
+ /** Upload speed in bytes per second */
152
+ uploadSpeed?: number;
153
+ /** Estimated time remaining in milliseconds */
154
+ timeRemaining?: number;
155
+ /** Error message if state is 'error' */
156
+ error?: Error;
157
+ }
158
+
159
+ /**
160
+ * Single file upload state
161
+ */
162
+ export interface SingleUploadState extends UploadProgress {
163
+ /** File name */
164
+ fileName: string;
165
+ /** File size */
166
+ fileSize: number;
167
+ /** Result from server after successful upload */
168
+ result?: unknown;
169
+ }
170
+
171
+ /**
172
+ * Multi-file upload item
173
+ */
174
+ export interface UploadItem {
175
+ /** Unique identifier for this upload */
176
+ id: string;
177
+ /** File information */
178
+ file: FilePickResult;
179
+ /** Upload progress */
180
+ progress: UploadProgress;
181
+ /** Result from server if successful */
182
+ result?: unknown;
183
+ }
184
+
185
+ /**
186
+ * Multi-file upload state
187
+ */
188
+ export interface MultiUploadState {
189
+ /** All upload items */
190
+ items: UploadItem[];
191
+ /** Aggregate progress */
192
+ progress: number;
193
+ /** Total uploads */
194
+ total: number;
195
+ /** Completed uploads */
196
+ completed: number;
197
+ /** Failed uploads */
198
+ failed: number;
199
+ }
200
+
201
+ /**
202
+ * Flow upload state
203
+ */
204
+ export interface FlowUploadState {
205
+ /** Job ID for the flow */
206
+ jobId?: string;
207
+ /** Overall state */
208
+ state: UploadState;
209
+ /** Progress percentage */
210
+ progress: number;
211
+ /** Flow execution results */
212
+ result?: unknown;
213
+ /** Error if failed */
214
+ error?: Error;
215
+ }
216
+
217
+ /**
218
+ * Options for single upload hook
219
+ */
220
+ export interface UseSingleUploadOptions {
221
+ /** Flow ID to use for upload */
222
+ flowId?: string;
223
+ /** Field name for file */
224
+ fieldName?: string;
225
+ /** Additional form data */
226
+ metadata?: Record<string, string>;
227
+ /** Enable retry on failure */
228
+ autoRetry?: boolean;
229
+ /** Maximum retry attempts */
230
+ maxRetries?: number;
231
+ }
232
+
233
+ /**
234
+ * Options for multi-upload hook
235
+ */
236
+ export interface UseMultiUploadOptions {
237
+ /** Max concurrent uploads */
238
+ maxConcurrent?: number;
239
+ /** Additional form data for all uploads */
240
+ metadata?: Record<string, string>;
241
+ /** Called when a file upload succeeds */
242
+ onSuccess?: (result: unknown) => void;
243
+ /** Called when a file upload fails */
244
+ onError?: (error: Error) => void;
245
+ }
246
+
247
+ /**
248
+ * Options for flow upload hook
249
+ */
250
+ export interface UseFlowUploadOptions {
251
+ /** Flow ID to execute */
252
+ flowId: string;
253
+ /** Storage ID for the upload */
254
+ storageId: string;
255
+ /** Output node ID for the flow */
256
+ outputNodeId?: string;
257
+ /** Metadata to pass to flow */
258
+ metadata?: Record<string, unknown>;
259
+ /** Called when upload succeeds */
260
+ onSuccess?: (result: unknown) => void;
261
+ /** Called when upload fails */
262
+ onError?: (error: Error) => void;
263
+ /** Called when upload progress updates */
264
+ onProgress?: (
265
+ progress: number,
266
+ bytesUploaded: number,
267
+ totalBytes: number | null,
268
+ ) => void;
269
+ /** Called when a chunk completes */
270
+ onChunkComplete?: (
271
+ chunkSize: number,
272
+ bytesAccepted: number,
273
+ bytesTotal: number | null,
274
+ ) => void;
275
+ }
276
+
277
+ /**
278
+ * Options for camera upload hook
279
+ */
280
+ export interface UseCameraUploadOptions {
281
+ /** Flow ID to use */
282
+ flowId?: string;
283
+ /** Camera options */
284
+ cameraOptions?: CameraOptions;
285
+ /** Additional metadata */
286
+ metadata?: Record<string, string>;
287
+ /** Called when upload succeeds */
288
+ onSuccess?: (result: unknown) => void;
289
+ /** Called when upload fails */
290
+ onError?: (error: Error) => void;
291
+ /** Called when upload progress updates */
292
+ onProgress?: (
293
+ progress: number,
294
+ bytesUploaded: number,
295
+ totalBytes: number | null,
296
+ ) => void;
297
+ }
298
+
299
+ /**
300
+ * Options for gallery upload hook
301
+ */
302
+ export interface UseGalleryUploadOptions {
303
+ /** Flow ID to use */
304
+ flowId?: string;
305
+ /** Allow multiple selection */
306
+ allowMultiple?: boolean;
307
+ /** Media type: 'photo', 'video', or 'mixed' */
308
+ mediaType?: "photo" | "video" | "mixed";
309
+ /** Additional metadata */
310
+ metadata?: Record<string, string>;
311
+ /** Called when upload succeeds */
312
+ onSuccess?: (result: unknown) => void;
313
+ /** Called when upload fails */
314
+ onError?: (error: Error) => void;
315
+ /** Called when upload progress updates */
316
+ onProgress?: (
317
+ progress: number,
318
+ bytesUploaded: number,
319
+ totalBytes: number | null,
320
+ ) => void;
321
+ }
322
+
323
+ /**
324
+ * Options for file upload hook
325
+ */
326
+ export interface UseFileUploadOptions {
327
+ /** Flow ID to use */
328
+ flowId?: string;
329
+ /** Allowed file types */
330
+ allowedTypes?: string[];
331
+ /** Additional metadata */
332
+ metadata?: Record<string, string>;
333
+ /** Called when upload succeeds */
334
+ onSuccess?: (result: unknown) => void;
335
+ /** Called when upload fails */
336
+ onError?: (error: Error) => void;
337
+ /** Called when upload progress updates */
338
+ onProgress?: (
339
+ progress: number,
340
+ bytesUploaded: number,
341
+ totalBytes: number | null,
342
+ ) => void;
343
+ }
344
+
345
+ /**
346
+ * Metrics for upload performance
347
+ */
348
+ export interface UploadMetrics {
349
+ /** Total bytes uploaded */
350
+ totalBytes: number;
351
+ /** Total upload duration in milliseconds */
352
+ durationMs: number;
353
+ /** Average upload speed in bytes/second */
354
+ avgSpeed: number;
355
+ /** Peak upload speed in bytes/second */
356
+ peakSpeed: number;
357
+ /** Number of retries */
358
+ retries: number;
359
+ }
@@ -0,0 +1 @@
1
+ export type ReactNativeUploadInput = Blob | File | string | { uri: string };
@@ -0,0 +1,201 @@
1
+ /**
2
+ * File utility functions for React Native uploads
3
+ */
4
+
5
+ /**
6
+ * Format file size to human readable string
7
+ * @param bytes - Size in bytes
8
+ * @returns Formatted size string (e.g., "1.5 MB")
9
+ */
10
+ export function formatFileSize(bytes: number): string {
11
+ if (bytes === 0) return "0 Bytes";
12
+
13
+ const k = 1024;
14
+ const sizes = ["Bytes", "KB", "MB", "GB"];
15
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
16
+
17
+ return `${Math.round((bytes / k ** i) * 100) / 100} ${sizes[i]}`;
18
+ }
19
+
20
+ /**
21
+ * Get MIME type from file name
22
+ * @param fileName - File name with extension
23
+ * @returns MIME type or 'application/octet-stream' as fallback
24
+ */
25
+ export function getMimeTypeFromFileName(fileName: string): string {
26
+ const mimeTypes: Record<string, string> = {
27
+ // Images
28
+ ".jpg": "image/jpeg",
29
+ ".jpeg": "image/jpeg",
30
+ ".png": "image/png",
31
+ ".gif": "image/gif",
32
+ ".bmp": "image/bmp",
33
+ ".webp": "image/webp",
34
+ ".svg": "image/svg+xml",
35
+
36
+ // Videos
37
+ ".mp4": "video/mp4",
38
+ ".avi": "video/x-msvideo",
39
+ ".mov": "video/quicktime",
40
+ ".wmv": "video/x-ms-wmv",
41
+ ".flv": "video/x-flv",
42
+ ".mkv": "video/x-matroska",
43
+ ".webm": "video/webm",
44
+
45
+ // Audio
46
+ ".mp3": "audio/mpeg",
47
+ ".wav": "audio/wav",
48
+ ".aac": "audio/aac",
49
+ ".flac": "audio/flac",
50
+ ".m4a": "audio/mp4",
51
+
52
+ // Documents
53
+ ".pdf": "application/pdf",
54
+ ".doc": "application/msword",
55
+ ".docx":
56
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
57
+ ".xls": "application/vnd.ms-excel",
58
+ ".xlsx":
59
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
60
+ ".ppt": "application/vnd.ms-powerpoint",
61
+ ".pptx":
62
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
63
+ ".txt": "text/plain",
64
+ ".csv": "text/csv",
65
+ ".json": "application/json",
66
+ ".xml": "application/xml",
67
+ ".zip": "application/zip",
68
+ };
69
+
70
+ const ext = fileName.toLowerCase().slice(fileName.lastIndexOf("."));
71
+ return mimeTypes[ext] || "application/octet-stream";
72
+ }
73
+
74
+ /**
75
+ * Check if file type is allowed
76
+ * @param fileName - File name to check
77
+ * @param allowedTypes - Array of allowed MIME types (e.g., ['image/jpeg', 'image/png'])
78
+ * @returns True if file type is allowed
79
+ */
80
+ export function isFileTypeAllowed(
81
+ fileName: string,
82
+ allowedTypes: string[],
83
+ ): boolean {
84
+ if (!allowedTypes || allowedTypes.length === 0) {
85
+ return true;
86
+ }
87
+
88
+ const mimeType = getMimeTypeFromFileName(fileName);
89
+ return allowedTypes.some((allowed) => {
90
+ if (allowed.endsWith("/*")) {
91
+ // Handle wildcard patterns like 'image/*'
92
+ const [type] = allowed.split("/");
93
+ return mimeType.startsWith(`${type}/`);
94
+ }
95
+ return allowed === mimeType;
96
+ });
97
+ }
98
+
99
+ /**
100
+ * Check if file size is within limits
101
+ * @param fileSize - File size in bytes
102
+ * @param maxSize - Maximum allowed size in bytes (optional)
103
+ * @param minSize - Minimum allowed size in bytes (optional)
104
+ * @returns True if file size is within limits
105
+ */
106
+ export function isFileSizeValid(
107
+ fileSize: number,
108
+ maxSize?: number,
109
+ minSize?: number,
110
+ ): boolean {
111
+ if (maxSize !== undefined && fileSize > maxSize) {
112
+ return false;
113
+ }
114
+
115
+ if (minSize !== undefined && fileSize < minSize) {
116
+ return false;
117
+ }
118
+
119
+ return true;
120
+ }
121
+
122
+ /**
123
+ * Get file extension
124
+ * @param fileName - File name
125
+ * @returns File extension without dot (e.g., 'pdf' for 'document.pdf')
126
+ */
127
+ export function getFileExtension(fileName: string): string {
128
+ const lastDot = fileName.lastIndexOf(".");
129
+ if (lastDot === -1) return "";
130
+ return fileName.slice(lastDot + 1).toLowerCase();
131
+ }
132
+
133
+ /**
134
+ * Get file name without extension
135
+ * @param fileName - File name
136
+ * @returns File name without extension
137
+ */
138
+ export function getFileNameWithoutExtension(fileName: string): string {
139
+ const lastDot = fileName.lastIndexOf(".");
140
+ if (lastDot === -1) return fileName;
141
+ return fileName.slice(0, lastDot);
142
+ }
143
+
144
+ /**
145
+ * Check if file is an image
146
+ * @param fileName - File name
147
+ * @returns True if file is an image
148
+ */
149
+ export function isImageFile(fileName: string): boolean {
150
+ const imageExtensions = [
151
+ ".jpg",
152
+ ".jpeg",
153
+ ".png",
154
+ ".gif",
155
+ ".bmp",
156
+ ".webp",
157
+ ".svg",
158
+ ];
159
+ const ext = fileName.toLowerCase().slice(fileName.lastIndexOf("."));
160
+ return imageExtensions.includes(ext);
161
+ }
162
+
163
+ /**
164
+ * Check if file is a video
165
+ * @param fileName - File name
166
+ * @returns True if file is a video
167
+ */
168
+ export function isVideoFile(fileName: string): boolean {
169
+ const videoExtensions = [
170
+ ".mp4",
171
+ ".avi",
172
+ ".mov",
173
+ ".wmv",
174
+ ".flv",
175
+ ".mkv",
176
+ ".webm",
177
+ ];
178
+ const ext = fileName.toLowerCase().slice(fileName.lastIndexOf("."));
179
+ return videoExtensions.includes(ext);
180
+ }
181
+
182
+ /**
183
+ * Check if file is a document
184
+ * @param fileName - File name
185
+ * @returns True if file is a document
186
+ */
187
+ export function isDocumentFile(fileName: string): boolean {
188
+ const docExtensions = [
189
+ ".pdf",
190
+ ".doc",
191
+ ".docx",
192
+ ".xls",
193
+ ".xlsx",
194
+ ".ppt",
195
+ ".pptx",
196
+ ".txt",
197
+ ".csv",
198
+ ];
199
+ const ext = fileName.toLowerCase().slice(fileName.lastIndexOf("."));
200
+ return docExtensions.includes(ext);
201
+ }
@@ -0,0 +1,36 @@
1
+ // File helpers
2
+ export {
3
+ formatFileSize,
4
+ getFileExtension,
5
+ getFileNameWithoutExtension,
6
+ getMimeTypeFromFileName,
7
+ isDocumentFile,
8
+ isFileSizeValid,
9
+ isFileTypeAllowed,
10
+ isImageFile,
11
+ isVideoFile,
12
+ } from "./fileHelpers";
13
+ // Permission helpers
14
+ export {
15
+ getPermissionStatus,
16
+ hasPermissions,
17
+ openAppSettings,
18
+ PermissionStatus,
19
+ PermissionType,
20
+ requestCameraPermission,
21
+ requestPermissions,
22
+ requestPhotoLibraryPermission,
23
+ requestStorageReadPermission,
24
+ requestStorageWritePermission,
25
+ } from "./permissions";
26
+ // URI helpers
27
+ export {
28
+ getDirectoryFromUri,
29
+ getFileNameFromUri,
30
+ getMimeTypeFromUri,
31
+ isContentUri,
32
+ isFileUri,
33
+ normalizeUri,
34
+ pathToUri,
35
+ uriToPath,
36
+ } from "./uriHelpers";