@ammarahmed/react-native-upload 6.16.0 → 6.18.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.
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/com/appfolio/extensions/ContextExtensions.kt +63 -0
- package/android/src/main/java/com/appfolio/extensions/UploadExtensions.kt +57 -0
- package/android/src/main/java/com/appfolio/uploader/GlobalRequestObserverDelegate.kt +66 -0
- package/android/src/main/java/com/appfolio/uploader/ModifiedBinaryUploadRequest.kt +29 -0
- package/android/src/main/java/com/appfolio/uploader/ModifiedHttpUploadRequest.kt +57 -0
- package/android/src/main/java/com/appfolio/uploader/ModifiedMultipartUploadRequest.kt +60 -0
- package/android/src/main/java/com/appfolio/uploader/UploaderModule.kt +393 -0
- package/android/src/main/java/com/appfolio/uploader/UploaderReactPackage.java +32 -0
- package/android/src/main/java/com/appfolio/work/TaskCompletionNotifier.kt +47 -0
- package/android/src/main/java/com/appfolio/work/UploadManager.kt +109 -0
- package/android/src/main/java/com/appfolio/work/UploadWorker.kt +20 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +551 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handles HTTP background file uploads from an iOS or Android device.
|
|
3
|
+
*/
|
|
4
|
+
import {
|
|
5
|
+
NativeModules,
|
|
6
|
+
DeviceEventEmitter,
|
|
7
|
+
Platform,
|
|
8
|
+
EmitterSubscription,
|
|
9
|
+
} from 'react-native';
|
|
10
|
+
|
|
11
|
+
export type UploadEvent = 'progress' | 'error' | 'completed' | 'cancelled';
|
|
12
|
+
|
|
13
|
+
export type NotificationOptions = {
|
|
14
|
+
/**
|
|
15
|
+
* Enable or diasable notifications. Works only on Android version < 8.0 Oreo. On Android versions >= 8.0 Oreo is required by Google's policy to display a notification when a background service run { enabled: true }
|
|
16
|
+
*/
|
|
17
|
+
enabled: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Autoclear notification on complete { autoclear: true }
|
|
20
|
+
*/
|
|
21
|
+
autoClear: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Sets android notificaion channel { notificationChannel: "My-Upload-Service" }
|
|
24
|
+
*/
|
|
25
|
+
notificationChannel: string;
|
|
26
|
+
/**
|
|
27
|
+
* Sets whether or not to enable the notification sound when the upload gets completed with success or error { enableRingTone: true }
|
|
28
|
+
*/
|
|
29
|
+
enableRingTone: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Sets notification progress title { onProgressTitle: "Uploading" }
|
|
32
|
+
*/
|
|
33
|
+
onProgressTitle: string;
|
|
34
|
+
/**
|
|
35
|
+
* Sets notification progress message { onProgressMessage: "Uploading new video" }
|
|
36
|
+
*/
|
|
37
|
+
onProgressMessage: string;
|
|
38
|
+
/**
|
|
39
|
+
* Sets notification complete title { onCompleteTitle: "Upload finished" }
|
|
40
|
+
*/
|
|
41
|
+
onCompleteTitle: string;
|
|
42
|
+
/**
|
|
43
|
+
* Sets notification complete message { onCompleteMessage: "Your video has been uploaded" }
|
|
44
|
+
*/
|
|
45
|
+
onCompleteMessage: string;
|
|
46
|
+
/**
|
|
47
|
+
* Sets notification error title { onErrorTitle: "Upload error" }
|
|
48
|
+
*/
|
|
49
|
+
onErrorTitle: string;
|
|
50
|
+
/**
|
|
51
|
+
* Sets notification error message { onErrorMessage: "An error occured while uploading a video" }
|
|
52
|
+
*/
|
|
53
|
+
onErrorMessage: string;
|
|
54
|
+
/**
|
|
55
|
+
* Sets notification cancelled title { onCancelledTitle: "Upload cancelled" }
|
|
56
|
+
*/
|
|
57
|
+
onCancelledTitle: string;
|
|
58
|
+
/**
|
|
59
|
+
* Sets notification cancelled message { onCancelledMessage: "Video upload was cancelled" }
|
|
60
|
+
*/
|
|
61
|
+
onCancelledMessage: string;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type UploadOptions = {
|
|
65
|
+
url: string;
|
|
66
|
+
path: string;
|
|
67
|
+
method?: 'PUT' | 'POST';
|
|
68
|
+
type?: 'raw' | 'multipart';
|
|
69
|
+
field?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Provide this id to track uploads globally and avoid duplicate upload tasks
|
|
72
|
+
*/
|
|
73
|
+
customUploadId?: string;
|
|
74
|
+
parameters?: Record<string, string>;
|
|
75
|
+
headers?: Record<string, string>;
|
|
76
|
+
notification?: Partial<NotificationOptions>;
|
|
77
|
+
/**
|
|
78
|
+
* AppGroup defined in XCode for extensions. Necessary when trying to upload things via this library
|
|
79
|
+
* in the context of ShareExtension.
|
|
80
|
+
*/
|
|
81
|
+
appGroup?: string;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export interface MultipartUploadOptions extends UploadOptions {
|
|
85
|
+
type: 'multipart';
|
|
86
|
+
field: string;
|
|
87
|
+
parameters?: {
|
|
88
|
+
[index: string]: string;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface FileInfo {
|
|
93
|
+
exists: boolean;
|
|
94
|
+
extension?: string;
|
|
95
|
+
size?: number;
|
|
96
|
+
mimeType?: string;
|
|
97
|
+
name?: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface ProgressData {
|
|
101
|
+
id: string;
|
|
102
|
+
progress: number;
|
|
103
|
+
totalBytes: number;
|
|
104
|
+
uploadedBytes: number;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface ErrorData {
|
|
108
|
+
id: string;
|
|
109
|
+
error: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface CancelledData {
|
|
113
|
+
id: string;
|
|
114
|
+
error: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface CompletedData {
|
|
118
|
+
id: string;
|
|
119
|
+
responseCode?: number;
|
|
120
|
+
responseBody?: string | null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export type UploadEventData =
|
|
124
|
+
| ProgressData
|
|
125
|
+
| ErrorData
|
|
126
|
+
| CancelledData
|
|
127
|
+
| CompletedData;
|
|
128
|
+
|
|
129
|
+
const NativeModule =
|
|
130
|
+
NativeModules.VydiaRNFileUploader || NativeModules.RNFileUploader;
|
|
131
|
+
const eventPrefix = 'RNFileUploader-';
|
|
132
|
+
|
|
133
|
+
// for IOS, register event listeners or else they don't fire on DeviceEventEmitter
|
|
134
|
+
if (NativeModules.VydiaRNFileUploader) {
|
|
135
|
+
NativeModule.addListener(eventPrefix + 'progress');
|
|
136
|
+
NativeModule.addListener(eventPrefix + 'error');
|
|
137
|
+
NativeModule.addListener(eventPrefix + 'cancelled');
|
|
138
|
+
NativeModule.addListener(eventPrefix + 'completed');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export const UploadState = {
|
|
142
|
+
Cancelled: 'cancelled',
|
|
143
|
+
Completed: 'completed',
|
|
144
|
+
Pending: 'pending',
|
|
145
|
+
Running: 'running',
|
|
146
|
+
Error: 'error',
|
|
147
|
+
} as const;
|
|
148
|
+
|
|
149
|
+
export type UploadStatus = typeof UploadState[keyof typeof UploadState];
|
|
150
|
+
|
|
151
|
+
export interface UploadChangeEvent {
|
|
152
|
+
status: UploadStatus;
|
|
153
|
+
progress?: number;
|
|
154
|
+
error?: string;
|
|
155
|
+
responseCode?: number;
|
|
156
|
+
responseBody?: string | null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export interface UploadResult {
|
|
160
|
+
status: UploadStatus;
|
|
161
|
+
error?: string;
|
|
162
|
+
responseCode?: number;
|
|
163
|
+
responseBody?: string | null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface NativeUploadInfo {
|
|
167
|
+
id: string;
|
|
168
|
+
state: UploadStatus;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Global registry to track active uploads and prevent duplicates
|
|
172
|
+
class UploadRegistry {
|
|
173
|
+
public static uploads: Map<string, Upload> = new Map();
|
|
174
|
+
|
|
175
|
+
static register(upload: Upload): void {
|
|
176
|
+
const id = upload.getId();
|
|
177
|
+
if (id) {
|
|
178
|
+
this.uploads.set(id, upload);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
static unregister(upload: Upload): void {
|
|
183
|
+
const id = upload.getId();
|
|
184
|
+
if (id) {
|
|
185
|
+
this.uploads.delete(id);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
static getById(id: string): Upload | undefined {
|
|
190
|
+
return this.uploads.get(id);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
static has(id: string): boolean {
|
|
194
|
+
return this.uploads.has(id);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
static clear(): void {
|
|
198
|
+
this.uploads.clear();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
class Upload {
|
|
203
|
+
private uploadId: string | null = null;
|
|
204
|
+
private config: UploadOptions;
|
|
205
|
+
private subscriptions: EmitterSubscription[] = [];
|
|
206
|
+
private status: UploadStatus = UploadState.Pending;
|
|
207
|
+
private startPromise: Promise<UploadResult> | null = null;
|
|
208
|
+
private resolveStart: ((result: UploadResult) => void) | null = null;
|
|
209
|
+
private rejectStart: ((error: Error) => void) | null = null;
|
|
210
|
+
private changeCallback: ((event: UploadChangeEvent) => void) | null = null;
|
|
211
|
+
|
|
212
|
+
constructor(config: UploadOptions) {
|
|
213
|
+
this.config = config;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Create a new upload instance or return existing one for the same path
|
|
218
|
+
*/
|
|
219
|
+
static create(config: UploadOptions | MultipartUploadOptions): Upload {
|
|
220
|
+
// Check if there's an existing upload for this upload id
|
|
221
|
+
const existingUpload = config.customUploadId
|
|
222
|
+
? UploadRegistry.getById(config.customUploadId)
|
|
223
|
+
: null;
|
|
224
|
+
if (existingUpload && existingUpload.isRunning()) {
|
|
225
|
+
console.warn(
|
|
226
|
+
`Upload already in progress for path: ${
|
|
227
|
+
config.path
|
|
228
|
+
}. Returning existing upload.`,
|
|
229
|
+
);
|
|
230
|
+
return existingUpload;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const upload = new Upload(config);
|
|
234
|
+
return upload;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Resume an existing upload by ID (useful after app restart)
|
|
239
|
+
*/
|
|
240
|
+
static async resume(uploadId: string): Promise<Upload | null> {
|
|
241
|
+
// Check if already tracked
|
|
242
|
+
const existingUpload = UploadRegistry.getById(uploadId);
|
|
243
|
+
if (existingUpload) {
|
|
244
|
+
return existingUpload;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Get all uploads from native side
|
|
248
|
+
const nativeUploads = await getAllUploads();
|
|
249
|
+
const uploadInfo = nativeUploads.find(u => u.id === uploadId);
|
|
250
|
+
|
|
251
|
+
if (!uploadInfo) {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Create a minimal upload instance for resumed upload
|
|
256
|
+
const upload = new Upload({ url: '', path: '' }); // We don't have the original config
|
|
257
|
+
upload.uploadId = uploadId;
|
|
258
|
+
upload.status = upload.mapNativeStateToStatus(uploadInfo.state);
|
|
259
|
+
|
|
260
|
+
// Register and setup listeners
|
|
261
|
+
UploadRegistry.register(upload);
|
|
262
|
+
upload.setupEventListeners();
|
|
263
|
+
|
|
264
|
+
return upload;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Get all currently tracked uploads
|
|
269
|
+
*/
|
|
270
|
+
static getAll(): Upload[] {
|
|
271
|
+
const uploads: Upload[] = [];
|
|
272
|
+
UploadRegistry.uploads.forEach(upload => uploads.push(upload));
|
|
273
|
+
return uploads;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Set a callback to be called whenever the upload state changes
|
|
278
|
+
*/
|
|
279
|
+
onChange(callback: (event: UploadChangeEvent) => void): this {
|
|
280
|
+
this.changeCallback = callback;
|
|
281
|
+
return this;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Start the upload - resolves when upload completes, is cancelled, or errors
|
|
286
|
+
*/
|
|
287
|
+
async start(): Promise<UploadResult> {
|
|
288
|
+
if (this.uploadId) {
|
|
289
|
+
throw new Error('Upload already started');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (this.startPromise) {
|
|
293
|
+
return this.startPromise;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Check if there's an existing upload for this path in native side
|
|
297
|
+
if (this.config.path) {
|
|
298
|
+
const nativeUploads = await getAllUploads();
|
|
299
|
+
const existingUpload = nativeUploads.find(
|
|
300
|
+
u => u.state === 'running' || u.state === 'pending',
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
if (existingUpload && !this.config.customUploadId) {
|
|
304
|
+
console.warn(
|
|
305
|
+
`Found existing upload in native side. Resuming upload: ${
|
|
306
|
+
existingUpload.id
|
|
307
|
+
}`,
|
|
308
|
+
);
|
|
309
|
+
this.uploadId = existingUpload.id;
|
|
310
|
+
this.status = this.mapNativeStateToStatus(existingUpload.state);
|
|
311
|
+
UploadRegistry.register(this);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
this.startPromise = new Promise<UploadResult>((resolve, reject) => {
|
|
316
|
+
this.resolveStart = resolve;
|
|
317
|
+
this.rejectStart = reject;
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// Register event listeners
|
|
321
|
+
this.setupEventListeners();
|
|
322
|
+
|
|
323
|
+
// If we resumed an existing upload, don't call native startUpload again
|
|
324
|
+
if (!this.uploadId) {
|
|
325
|
+
try {
|
|
326
|
+
this.uploadId = await NativeModule.startUpload(this.config);
|
|
327
|
+
this.updateStatus(UploadState.Running);
|
|
328
|
+
UploadRegistry.register(this);
|
|
329
|
+
} catch (error) {
|
|
330
|
+
this.cleanup();
|
|
331
|
+
if (this.rejectStart) {
|
|
332
|
+
this.rejectStart(error as Error);
|
|
333
|
+
}
|
|
334
|
+
throw error;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return this.startPromise;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
private setupEventListeners(): void {
|
|
342
|
+
// Progress listener
|
|
343
|
+
const progressSubscription = DeviceEventEmitter.addListener(
|
|
344
|
+
eventPrefix + 'progress',
|
|
345
|
+
(data: ProgressData) => {
|
|
346
|
+
if (this.uploadId && data.id === this.uploadId) {
|
|
347
|
+
this.notifyChange({
|
|
348
|
+
status: UploadState.Running,
|
|
349
|
+
progress: data.progress,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
);
|
|
354
|
+
this.subscriptions.push(progressSubscription);
|
|
355
|
+
|
|
356
|
+
// Completed listener
|
|
357
|
+
const completedSubscription = DeviceEventEmitter.addListener(
|
|
358
|
+
eventPrefix + 'completed',
|
|
359
|
+
(data: CompletedData) => {
|
|
360
|
+
if (this.uploadId && data.id === this.uploadId) {
|
|
361
|
+
this.updateStatus(
|
|
362
|
+
UploadState.Completed,
|
|
363
|
+
undefined,
|
|
364
|
+
data.responseCode,
|
|
365
|
+
data.responseBody,
|
|
366
|
+
);
|
|
367
|
+
if (this.resolveStart) {
|
|
368
|
+
this.resolveStart({
|
|
369
|
+
status: 'completed',
|
|
370
|
+
responseCode: data.responseCode,
|
|
371
|
+
responseBody: data.responseBody,
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
this.cleanup();
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
);
|
|
378
|
+
this.subscriptions.push(completedSubscription);
|
|
379
|
+
|
|
380
|
+
// Error listener
|
|
381
|
+
const errorSubscription = DeviceEventEmitter.addListener(
|
|
382
|
+
eventPrefix + 'error',
|
|
383
|
+
(data: ErrorData) => {
|
|
384
|
+
if (this.uploadId && data.id === this.uploadId) {
|
|
385
|
+
this.updateStatus(UploadState.Error, data.error);
|
|
386
|
+
if (this.resolveStart) {
|
|
387
|
+
this.resolveStart({ status: 'error', error: data.error });
|
|
388
|
+
}
|
|
389
|
+
this.cleanup();
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
);
|
|
393
|
+
this.subscriptions.push(errorSubscription);
|
|
394
|
+
|
|
395
|
+
// Cancelled listener
|
|
396
|
+
const cancelledSubscription = DeviceEventEmitter.addListener(
|
|
397
|
+
eventPrefix + 'cancelled',
|
|
398
|
+
(data: CancelledData) => {
|
|
399
|
+
if (this.uploadId && data.id === this.uploadId) {
|
|
400
|
+
this.updateStatus(UploadState.Cancelled, data.error);
|
|
401
|
+
if (this.resolveStart) {
|
|
402
|
+
this.resolveStart({ status: 'cancelled', error: data.error });
|
|
403
|
+
}
|
|
404
|
+
this.cleanup();
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
);
|
|
408
|
+
this.subscriptions.push(cancelledSubscription);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
private updateStatus(
|
|
412
|
+
status: UploadStatus,
|
|
413
|
+
error?: string,
|
|
414
|
+
responseCode?: number,
|
|
415
|
+
responseBody?: string | null,
|
|
416
|
+
): void {
|
|
417
|
+
this.status = status;
|
|
418
|
+
this.notifyChange({ status, error, responseCode, responseBody });
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
private notifyChange(event: UploadChangeEvent): void {
|
|
422
|
+
if (this.changeCallback) {
|
|
423
|
+
this.changeCallback(event);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
private mapNativeStateToStatus(state: string): UploadStatus {
|
|
428
|
+
switch (state) {
|
|
429
|
+
case 'running':
|
|
430
|
+
return UploadState.Running;
|
|
431
|
+
case 'pending':
|
|
432
|
+
return UploadState.Pending;
|
|
433
|
+
case 'cancelled':
|
|
434
|
+
return UploadState.Cancelled;
|
|
435
|
+
case 'completed':
|
|
436
|
+
return UploadState.Completed;
|
|
437
|
+
default:
|
|
438
|
+
return UploadState.Pending;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Cancel the upload
|
|
444
|
+
*/
|
|
445
|
+
async cancel(): Promise<boolean> {
|
|
446
|
+
if (!this.uploadId) {
|
|
447
|
+
throw new Error('Upload not started');
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
try {
|
|
451
|
+
const result = await NativeModule.cancelUpload(this.uploadId);
|
|
452
|
+
// Don't cleanup here - let the cancelled event handle it
|
|
453
|
+
return result;
|
|
454
|
+
} catch (error) {
|
|
455
|
+
this.cleanup();
|
|
456
|
+
throw error;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Get the current upload status
|
|
462
|
+
*/
|
|
463
|
+
getStatus(): UploadStatus {
|
|
464
|
+
return this.status;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Get the upload ID
|
|
469
|
+
*/
|
|
470
|
+
getId(): string | null {
|
|
471
|
+
return this.uploadId;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Get the file path
|
|
476
|
+
*/
|
|
477
|
+
getPath(): string {
|
|
478
|
+
return this.config.path;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Check if upload is in progress
|
|
483
|
+
*/
|
|
484
|
+
isRunning(): boolean {
|
|
485
|
+
return this.status === UploadState.Running;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Clean up listeners
|
|
490
|
+
*/
|
|
491
|
+
private cleanup(): void {
|
|
492
|
+
this.subscriptions.forEach(sub => sub.remove());
|
|
493
|
+
this.subscriptions = [];
|
|
494
|
+
this.resolveStart = null;
|
|
495
|
+
this.rejectStart = null;
|
|
496
|
+
UploadRegistry.unregister(this);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Legacy API exports for backward compatibility
|
|
501
|
+
export const getFileInfo = (path: string): Promise<FileInfo> => {
|
|
502
|
+
return NativeModule.getFileInfo(path).then((data: FileInfo) => {
|
|
503
|
+
if (data.size) {
|
|
504
|
+
data.size = +data.size;
|
|
505
|
+
}
|
|
506
|
+
return data;
|
|
507
|
+
});
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
export const startUpload = (options: UploadOptions): Promise<string> =>
|
|
511
|
+
NativeModule.startUpload(options);
|
|
512
|
+
|
|
513
|
+
export const cancelUpload = (cancelUploadId: string): Promise<boolean> => {
|
|
514
|
+
if (typeof cancelUploadId !== 'string') {
|
|
515
|
+
return Promise.reject(new Error('Upload ID must be a string'));
|
|
516
|
+
}
|
|
517
|
+
return NativeModule.cancelUpload(cancelUploadId);
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
export const addListener = (
|
|
521
|
+
eventType: UploadEvent,
|
|
522
|
+
uploadId: string,
|
|
523
|
+
listener: (data: UploadEventData) => void,
|
|
524
|
+
): EmitterSubscription => {
|
|
525
|
+
return DeviceEventEmitter.addListener(
|
|
526
|
+
eventPrefix + eventType,
|
|
527
|
+
(data: UploadEventData) => {
|
|
528
|
+
if (!uploadId || !data || !('id' in data) || data.id === uploadId) {
|
|
529
|
+
listener(data);
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
);
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
export const canSuspendIfBackground = (): void => {
|
|
536
|
+
if (Platform.OS === 'ios') {
|
|
537
|
+
NativeModule.canSuspendIfBackground();
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
export const shouldLimitNetwork = (limit: boolean): void => {
|
|
542
|
+
NativeModule.shouldLimitNetwork(limit);
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
export const getAllUploads = (): Promise<NativeUploadInfo[]> => {
|
|
546
|
+
return NativeModule.getAllUploads();
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
export { Upload };
|
|
550
|
+
|
|
551
|
+
export default Upload;
|