@ammarahmed/react-native-upload 6.33.0 → 7.0.0-alpha.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/.eslintignore +1 -2
- package/README.md +166 -1
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/appfolio/uploader/MultipartCompletionService.kt +33 -0
- package/android/src/main/java/com/appfolio/uploader/MultipartUploadService.kt +200 -0
- package/android/src/main/java/com/appfolio/uploader/MultipartUploader.kt +787 -0
- package/android/src/main/java/com/appfolio/uploader/UploaderModule.kt +76 -2
- package/dist/index.d.ts +161 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +318 -9
- package/ios/RNFileUploader.m +52 -1
- package/ios/RNMultipartUploader.h +28 -0
- package/ios/RNMultipartUploader.m +748 -0
- package/package.json +3 -3
- package/src/index.ts +404 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ammarahmed/react-native-upload",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0-alpha.0",
|
|
4
4
|
"description": "Cross platform http post file uploader with Android and iOS background support.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -40,12 +40,12 @@
|
|
|
40
40
|
"@semantic-release/github": "^8.0.0",
|
|
41
41
|
"@semantic-release/npm": "^9.0.0",
|
|
42
42
|
"@semantic-release/release-notes-generator": "^10.0.0",
|
|
43
|
-
"react-native": "0.82.1",
|
|
44
43
|
"eslint": "^6.8.0",
|
|
45
44
|
"husky": "^4.2.3",
|
|
46
45
|
"lint-staged": "^10.0.8",
|
|
46
|
+
"react-native": "0.82.1",
|
|
47
47
|
"semantic-release": "^19.0.2",
|
|
48
|
-
"typescript": "5.9.3"
|
|
48
|
+
"typescript": "^5.9.3"
|
|
49
49
|
},
|
|
50
50
|
"release": {
|
|
51
51
|
"plugins": [
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Handles HTTP background file uploads from an iOS or Android device.
|
|
3
3
|
*/
|
|
4
4
|
import {
|
|
5
|
+
AppRegistry,
|
|
5
6
|
NativeModules,
|
|
6
7
|
DeviceEventEmitter,
|
|
7
8
|
Platform,
|
|
@@ -33,9 +34,21 @@ export type NotificationOptions = {
|
|
|
33
34
|
*/
|
|
34
35
|
onProgressTitle: string;
|
|
35
36
|
/**
|
|
36
|
-
* Sets notification progress message { onProgressMessage: "Uploading new video" }
|
|
37
|
+
* Sets notification progress message. For multipart uploads {progress} is replaced with the percentage { onProgressMessage: "Uploading new video" }
|
|
37
38
|
*/
|
|
38
39
|
onProgressMessage: string;
|
|
40
|
+
/**
|
|
41
|
+
* Sets multipart upload notification start message { onStartMessage: "Starting upload..." }
|
|
42
|
+
*/
|
|
43
|
+
onStartMessage: string;
|
|
44
|
+
/**
|
|
45
|
+
* Sets multipart upload notification message when resuming { onResumeMessage: "Resuming upload..." }
|
|
46
|
+
*/
|
|
47
|
+
onResumeMessage: string;
|
|
48
|
+
/**
|
|
49
|
+
* Sets the Android notification channel name shown in system settings { notificationChannelName: "Uploads" }
|
|
50
|
+
*/
|
|
51
|
+
notificationChannelName: string;
|
|
39
52
|
/**
|
|
40
53
|
* Sets notification complete title { onCompleteTitle: "Upload finished" }
|
|
41
54
|
*/
|
|
@@ -126,6 +139,95 @@ export type UploadEventData =
|
|
|
126
139
|
| CancelledData
|
|
127
140
|
| CompletedData;
|
|
128
141
|
|
|
142
|
+
export type MultipartEventType =
|
|
143
|
+
| "progress"
|
|
144
|
+
| "error"
|
|
145
|
+
| "completed"
|
|
146
|
+
| "cancelled";
|
|
147
|
+
|
|
148
|
+
export interface MultipartS3Options {
|
|
149
|
+
/**
|
|
150
|
+
* Unique upload ID to track the upload.
|
|
151
|
+
*/
|
|
152
|
+
uploadId: string;
|
|
153
|
+
/**
|
|
154
|
+
* Path to the local file to upload (e.g. /path/to/file or file:///path/to/file).
|
|
155
|
+
*/
|
|
156
|
+
path: string;
|
|
157
|
+
/**
|
|
158
|
+
* Array of presigned URLs for each chunk in sequence.
|
|
159
|
+
*/
|
|
160
|
+
parts: string[];
|
|
161
|
+
/**
|
|
162
|
+
* Maximum parallel chunk uploads (default: 3).
|
|
163
|
+
*/
|
|
164
|
+
maxParallel?: number;
|
|
165
|
+
/**
|
|
166
|
+
* Notification options for background service (Android).
|
|
167
|
+
*/
|
|
168
|
+
notification?: Partial<NotificationOptions>;
|
|
169
|
+
/**
|
|
170
|
+
* AppGroup defined in Xcode for extensions (iOS).
|
|
171
|
+
*/
|
|
172
|
+
appGroup?: string;
|
|
173
|
+
/**
|
|
174
|
+
* Fixed-length array of previously uploaded chunk ETags (matching parts array length)
|
|
175
|
+
* for resuming an existing upload session. Completed parts carry their ETag string,
|
|
176
|
+
* while uncompleted parts carry empty string "".
|
|
177
|
+
* Already uploaded chunks will be skipped and pre-filled with these ETags.
|
|
178
|
+
*/
|
|
179
|
+
existingEtags?: string[];
|
|
180
|
+
/**
|
|
181
|
+
* Whether the upload can survive the app process being killed (default: true).
|
|
182
|
+
* Resumable uploads are persisted natively, resumed after a restart and can
|
|
183
|
+
* be finished later through getMultipartS3Uploads. When false, the upload
|
|
184
|
+
* still keeps running while the app is in the background but nothing is
|
|
185
|
+
* persisted, so it is gone if the app process dies.
|
|
186
|
+
*/
|
|
187
|
+
resumable?: boolean;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export interface MultipartProgressEvent {
|
|
191
|
+
type: string;
|
|
192
|
+
uploadId: string;
|
|
193
|
+
progress?: number;
|
|
194
|
+
bytesUploaded?: number;
|
|
195
|
+
totalBytes?: number;
|
|
196
|
+
chunkIndex?: number;
|
|
197
|
+
etag?: string;
|
|
198
|
+
etags?: string[];
|
|
199
|
+
errorMessage?: string;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export type MultipartUploadStatus = "running" | "paused" | "completed" | "failed";
|
|
203
|
+
|
|
204
|
+
export interface MultipartPendingUpload {
|
|
205
|
+
uploadId: string;
|
|
206
|
+
status: MultipartUploadStatus;
|
|
207
|
+
progress: number;
|
|
208
|
+
bytesUploaded: number;
|
|
209
|
+
totalBytes: number;
|
|
210
|
+
etags: string[];
|
|
211
|
+
error: string | null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export interface MultipartCompletionEvent {
|
|
215
|
+
uploadId: string;
|
|
216
|
+
status: "completed" | "failed";
|
|
217
|
+
etags: string[];
|
|
218
|
+
error: string | null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export type MultipartCompletionHandler = (
|
|
222
|
+
event: MultipartCompletionEvent,
|
|
223
|
+
) => Promise<void> | void;
|
|
224
|
+
|
|
225
|
+
export interface MultipartS3Result {
|
|
226
|
+
uploadId: string;
|
|
227
|
+
success: boolean;
|
|
228
|
+
etags: string[];
|
|
229
|
+
}
|
|
230
|
+
|
|
129
231
|
const NativeModule = NativeModules.RNFileUploader;
|
|
130
232
|
const eventPrefix = 'RNFileUploader-';
|
|
131
233
|
|
|
@@ -135,6 +237,68 @@ if (NativeModules.RNFileUploader && NativeModule.addListener) {
|
|
|
135
237
|
NativeModule.addListener(eventPrefix + 'error');
|
|
136
238
|
NativeModule.addListener(eventPrefix + 'cancelled');
|
|
137
239
|
NativeModule.addListener(eventPrefix + 'completed');
|
|
240
|
+
NativeModule.addListener(eventPrefix + 'multipart-progress');
|
|
241
|
+
NativeModule.addListener(eventPrefix + 'multipart-error');
|
|
242
|
+
NativeModule.addListener(eventPrefix + 'multipart-cancelled');
|
|
243
|
+
NativeModule.addListener(eventPrefix + 'multipart-completed');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
let multipartCompletionHandler: MultipartCompletionHandler | null = null;
|
|
247
|
+
const runningCompletions = new Map<string, Promise<void>>();
|
|
248
|
+
|
|
249
|
+
const runMultipartCompletion = (event: MultipartCompletionEvent): Promise<void> => {
|
|
250
|
+
const running = runningCompletions.get(event.uploadId);
|
|
251
|
+
if (running) {
|
|
252
|
+
return running;
|
|
253
|
+
}
|
|
254
|
+
const handler = multipartCompletionHandler;
|
|
255
|
+
if (!handler) {
|
|
256
|
+
return Promise.resolve();
|
|
257
|
+
}
|
|
258
|
+
const run = (async () => {
|
|
259
|
+
try {
|
|
260
|
+
await handler(event);
|
|
261
|
+
await NativeModule.acknowledgeMultipartUpload(event.uploadId);
|
|
262
|
+
} catch (error) {
|
|
263
|
+
console.warn(
|
|
264
|
+
`Multipart completion handler failed for ${event.uploadId}`,
|
|
265
|
+
error,
|
|
266
|
+
);
|
|
267
|
+
} finally {
|
|
268
|
+
runningCompletions.delete(event.uploadId);
|
|
269
|
+
}
|
|
270
|
+
})();
|
|
271
|
+
runningCompletions.set(event.uploadId, run);
|
|
272
|
+
return run;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
DeviceEventEmitter.addListener(eventPrefix + 'multipart-completed', (data: any) => {
|
|
276
|
+
runMultipartCompletion({
|
|
277
|
+
uploadId: data.uploadId,
|
|
278
|
+
status: 'completed',
|
|
279
|
+
etags: data.etags || [],
|
|
280
|
+
error: null,
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
DeviceEventEmitter.addListener(eventPrefix + 'multipart-error', (data: any) => {
|
|
285
|
+
runMultipartCompletion({
|
|
286
|
+
uploadId: data.uploadId,
|
|
287
|
+
status: 'failed',
|
|
288
|
+
etags: data.etags || [],
|
|
289
|
+
error: data.error || null,
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
if (Platform.OS === 'android') {
|
|
294
|
+
AppRegistry.registerHeadlessTask(
|
|
295
|
+
'RNMultipartUploadKeepAlive',
|
|
296
|
+
() => () => new Promise<void>(() => {}),
|
|
297
|
+
);
|
|
298
|
+
AppRegistry.registerHeadlessTask(
|
|
299
|
+
'RNMultipartUploadCompletion',
|
|
300
|
+
() => (data: MultipartCompletionEvent) => runMultipartCompletion(data),
|
|
301
|
+
);
|
|
138
302
|
}
|
|
139
303
|
|
|
140
304
|
export const UploadState = {
|
|
@@ -275,6 +439,90 @@ class Upload {
|
|
|
275
439
|
/**
|
|
276
440
|
* Get all currently tracked uploads
|
|
277
441
|
*/
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Create an S3 / Cloud multipart chunked upload instance
|
|
445
|
+
*/
|
|
446
|
+
static createMultipartS3(options: MultipartS3Options): MultipartS3Upload {
|
|
447
|
+
return MultipartS3Upload.create(options);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Start an S3 / Cloud multipart chunked upload directly
|
|
452
|
+
*/
|
|
453
|
+
static startMultipartS3(options: MultipartS3Options): Promise<MultipartS3Result> {
|
|
454
|
+
const upload = MultipartS3Upload.create(options);
|
|
455
|
+
return upload.start();
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Cancel an ongoing S3 multipart upload
|
|
460
|
+
*/
|
|
461
|
+
static cancelMultipartS3(uploadId: string): Promise<boolean> {
|
|
462
|
+
return MultipartS3Upload.cancel(uploadId);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Pause an ongoing S3 multipart upload
|
|
467
|
+
*/
|
|
468
|
+
static pauseMultipartS3(uploadId: string): Promise<boolean> {
|
|
469
|
+
return MultipartS3Upload.pause(uploadId);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Resume a paused S3 multipart upload
|
|
474
|
+
*/
|
|
475
|
+
static resumeMultipartS3(uploadId: string): Promise<boolean> {
|
|
476
|
+
return MultipartS3Upload.resume(uploadId);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Registers the function that finishes a multipart upload (for example by
|
|
481
|
+
* sending CompleteMultipartUpload) once every part has been uploaded. It is
|
|
482
|
+
* called when the app is running and, on Android, from a headless task when
|
|
483
|
+
* the upload finished while the app was not running. Register it at the top
|
|
484
|
+
* level of your entry file so it exists when the app is started in the
|
|
485
|
+
* background. The upload is acknowledged when the handler resolves.
|
|
486
|
+
*/
|
|
487
|
+
static setMultipartCompletionHandler(
|
|
488
|
+
handler: MultipartCompletionHandler | null,
|
|
489
|
+
): void {
|
|
490
|
+
multipartCompletionHandler = handler;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Lists multipart uploads known to the native side, including ones that
|
|
495
|
+
* finished while the app was suspended or relaunched in the background.
|
|
496
|
+
*/
|
|
497
|
+
static getMultipartS3Uploads(): Promise<MultipartPendingUpload[]> {
|
|
498
|
+
return NativeModule.getMultipartUploads();
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Removes the stored state of a completed or failed multipart upload.
|
|
503
|
+
*/
|
|
504
|
+
static acknowledgeMultipartS3(uploadId: string): Promise<boolean> {
|
|
505
|
+
return NativeModule.acknowledgeMultipartUpload(uploadId);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Add listener for multipart events
|
|
510
|
+
*/
|
|
511
|
+
static addMultipartListener(
|
|
512
|
+
eventType: MultipartEventType,
|
|
513
|
+
uploadId: string,
|
|
514
|
+
listener: (data: any) => void,
|
|
515
|
+
): EmitterSubscription {
|
|
516
|
+
return DeviceEventEmitter.addListener(
|
|
517
|
+
eventPrefix + "multipart-" + eventType,
|
|
518
|
+
(data: any) => {
|
|
519
|
+
if (!uploadId || !data || data.uploadId === uploadId) {
|
|
520
|
+
listener(data);
|
|
521
|
+
}
|
|
522
|
+
},
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
|
|
278
526
|
static getAll(): Upload[] {
|
|
279
527
|
const uploads: Upload[] = [];
|
|
280
528
|
UploadRegistry.uploads.forEach(upload => uploads.push(upload));
|
|
@@ -512,6 +760,160 @@ class Upload {
|
|
|
512
760
|
}
|
|
513
761
|
}
|
|
514
762
|
|
|
763
|
+
|
|
764
|
+
class MultipartS3Upload {
|
|
765
|
+
private options: MultipartS3Options;
|
|
766
|
+
private subscriptions: EmitterSubscription[] = [];
|
|
767
|
+
private startPromise: Promise<MultipartS3Result> | null = null;
|
|
768
|
+
private progressCallbacks: ((event: MultipartProgressEvent) => void)[] = [];
|
|
769
|
+
private static activeUploads: Map<string, MultipartS3Upload> = new Map();
|
|
770
|
+
|
|
771
|
+
constructor(options: MultipartS3Options) {
|
|
772
|
+
this.options = {
|
|
773
|
+
...options,
|
|
774
|
+
maxParallel: options.maxParallel ?? 3,
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
static create(options: MultipartS3Options): MultipartS3Upload {
|
|
779
|
+
const existing = MultipartS3Upload.activeUploads.get(options.uploadId);
|
|
780
|
+
if (existing) {
|
|
781
|
+
return existing;
|
|
782
|
+
}
|
|
783
|
+
const upload = new MultipartS3Upload(options);
|
|
784
|
+
MultipartS3Upload.activeUploads.set(options.uploadId, upload);
|
|
785
|
+
return upload;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
static getById(uploadId: string): MultipartS3Upload | undefined {
|
|
789
|
+
return MultipartS3Upload.activeUploads.get(uploadId);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
static async cancel(uploadId: string): Promise<boolean> {
|
|
793
|
+
const instance = MultipartS3Upload.activeUploads.get(uploadId);
|
|
794
|
+
if (instance) {
|
|
795
|
+
return instance.cancel();
|
|
796
|
+
}
|
|
797
|
+
return NativeModule.cancelMultipartUpload(uploadId);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
static async pause(uploadId: string): Promise<boolean> {
|
|
801
|
+
const instance = MultipartS3Upload.activeUploads.get(uploadId);
|
|
802
|
+
if (instance) {
|
|
803
|
+
return instance.pause();
|
|
804
|
+
}
|
|
805
|
+
return NativeModule.pauseMultipartUpload(uploadId);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
static async resume(uploadId: string): Promise<boolean> {
|
|
809
|
+
const instance = MultipartS3Upload.activeUploads.get(uploadId);
|
|
810
|
+
if (instance) {
|
|
811
|
+
return instance.resume();
|
|
812
|
+
}
|
|
813
|
+
return NativeModule.resumeMultipartUpload(uploadId);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
onProgress(callback: (event: MultipartProgressEvent) => void): this {
|
|
817
|
+
if (!this.progressCallbacks.includes(callback)) {
|
|
818
|
+
this.progressCallbacks.push(callback);
|
|
819
|
+
}
|
|
820
|
+
return this;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
getId(): string {
|
|
824
|
+
return this.options.uploadId;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
getPath(): string {
|
|
828
|
+
return this.options.path;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
async start(): Promise<MultipartS3Result> {
|
|
832
|
+
if (this.startPromise) {
|
|
833
|
+
return this.startPromise;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
this.setupEventListeners();
|
|
837
|
+
|
|
838
|
+
this.startPromise = (async () => {
|
|
839
|
+
try {
|
|
840
|
+
const nativeResult = await NativeModule.startMultipartUpload(this.options);
|
|
841
|
+
return nativeResult;
|
|
842
|
+
} finally {
|
|
843
|
+
this.cleanup();
|
|
844
|
+
}
|
|
845
|
+
})();
|
|
846
|
+
|
|
847
|
+
return this.startPromise;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
private setupEventListeners(): void {
|
|
851
|
+
const progressSub = DeviceEventEmitter.addListener(
|
|
852
|
+
eventPrefix + "multipart-progress",
|
|
853
|
+
(data: MultipartProgressEvent) => {
|
|
854
|
+
if (data.uploadId === this.options.uploadId) {
|
|
855
|
+
this.progressCallbacks.forEach(cb => cb(data));
|
|
856
|
+
}
|
|
857
|
+
},
|
|
858
|
+
);
|
|
859
|
+
this.subscriptions.push(progressSub);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
async cancel(): Promise<boolean> {
|
|
863
|
+
try {
|
|
864
|
+
const res = await NativeModule.cancelMultipartUpload(this.options.uploadId);
|
|
865
|
+
this.cleanup();
|
|
866
|
+
return res;
|
|
867
|
+
} catch (err) {
|
|
868
|
+
this.cleanup();
|
|
869
|
+
throw err;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
async pause(): Promise<boolean> {
|
|
874
|
+
return NativeModule.pauseMultipartUpload(this.options.uploadId);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
async resume(): Promise<boolean> {
|
|
878
|
+
return NativeModule.resumeMultipartUpload(this.options.uploadId);
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
private cleanup(): void {
|
|
882
|
+
this.subscriptions.forEach(sub => sub.remove());
|
|
883
|
+
this.subscriptions = [];
|
|
884
|
+
MultipartS3Upload.activeUploads.delete(this.options.uploadId);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
export const startMultipartS3 = (options: MultipartS3Options): Promise<MultipartS3Result> =>
|
|
889
|
+
Upload.startMultipartS3(options);
|
|
890
|
+
|
|
891
|
+
export const cancelMultipartS3 = (uploadId: string): Promise<boolean> =>
|
|
892
|
+
Upload.cancelMultipartS3(uploadId);
|
|
893
|
+
|
|
894
|
+
export const pauseMultipartS3 = (uploadId: string): Promise<boolean> =>
|
|
895
|
+
Upload.pauseMultipartS3(uploadId);
|
|
896
|
+
|
|
897
|
+
export const resumeMultipartS3 = (uploadId: string): Promise<boolean> =>
|
|
898
|
+
Upload.resumeMultipartS3(uploadId);
|
|
899
|
+
|
|
900
|
+
export const setMultipartCompletionHandler = (
|
|
901
|
+
handler: MultipartCompletionHandler | null,
|
|
902
|
+
): void => Upload.setMultipartCompletionHandler(handler);
|
|
903
|
+
|
|
904
|
+
export const getMultipartS3Uploads = (): Promise<MultipartPendingUpload[]> =>
|
|
905
|
+
Upload.getMultipartS3Uploads();
|
|
906
|
+
|
|
907
|
+
export const acknowledgeMultipartS3 = (uploadId: string): Promise<boolean> =>
|
|
908
|
+
Upload.acknowledgeMultipartS3(uploadId);
|
|
909
|
+
|
|
910
|
+
export const addMultipartListener = (
|
|
911
|
+
eventType: MultipartEventType,
|
|
912
|
+
uploadId: string,
|
|
913
|
+
listener: (data: any) => void,
|
|
914
|
+
): EmitterSubscription =>
|
|
915
|
+
Upload.addMultipartListener(eventType, uploadId, listener);
|
|
916
|
+
|
|
515
917
|
// Legacy API exports for backward compatibility
|
|
516
918
|
export const getFileInfo = (path: string): Promise<FileInfo> => {
|
|
517
919
|
return NativeModule.getFileInfo(path).then((data: FileInfo) => {
|
|
@@ -562,6 +964,6 @@ export const getAllUploads = async (): Promise<NativeUploadInfo[]> => {
|
|
|
562
964
|
return allUploads;
|
|
563
965
|
};
|
|
564
966
|
|
|
565
|
-
export { Upload };
|
|
967
|
+
export { Upload, MultipartS3Upload };
|
|
566
968
|
|
|
567
969
|
export default Upload;
|