@ammarahmed/react-native-upload 6.16.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/.circleci/config.yml +15 -0
- package/.eslintignore +2 -0
- package/.eslintrc.js +4 -0
- package/.prettierrc.js +6 -0
- package/CHANGELOG.md +3 -0
- package/CONTRIBUTING.md +8 -0
- package/LICENSE +21 -0
- package/README.md +391 -0
- package/android/build.gradle +82 -0
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +6 -0
- package/android/gradle.properties +6 -0
- package/android/gradlew +185 -0
- package/android/gradlew.bat +89 -0
- package/dist/index.d.ts +200 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +390 -0
- package/ios/RNFileUploader.h +8 -0
- package/ios/RNFileUploader.m +457 -0
- package/ios/VydiaRNFileUploader.xcodeproj/project.pbxproj +254 -0
- package/package.json +75 -0
- package/react-native-upload.podspec +18 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
12
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Handles HTTP background file uploads from an iOS or Android device.
|
|
39
|
+
*/
|
|
40
|
+
import { NativeModules, DeviceEventEmitter, Platform, } from 'react-native';
|
|
41
|
+
var NativeModule = NativeModules.VydiaRNFileUploader || NativeModules.RNFileUploader;
|
|
42
|
+
var eventPrefix = 'RNFileUploader-';
|
|
43
|
+
// for IOS, register event listeners or else they don't fire on DeviceEventEmitter
|
|
44
|
+
if (NativeModules.VydiaRNFileUploader) {
|
|
45
|
+
NativeModule.addListener(eventPrefix + 'progress');
|
|
46
|
+
NativeModule.addListener(eventPrefix + 'error');
|
|
47
|
+
NativeModule.addListener(eventPrefix + 'cancelled');
|
|
48
|
+
NativeModule.addListener(eventPrefix + 'completed');
|
|
49
|
+
}
|
|
50
|
+
export var UploadState = {
|
|
51
|
+
Cancelled: 'cancelled',
|
|
52
|
+
Completed: 'completed',
|
|
53
|
+
Pending: 'pending',
|
|
54
|
+
Running: 'running',
|
|
55
|
+
Error: 'error',
|
|
56
|
+
};
|
|
57
|
+
// Global registry to track active uploads and prevent duplicates
|
|
58
|
+
var UploadRegistry = /** @class */ (function () {
|
|
59
|
+
function UploadRegistry() {
|
|
60
|
+
}
|
|
61
|
+
UploadRegistry.register = function (upload) {
|
|
62
|
+
var id = upload.getId();
|
|
63
|
+
if (id) {
|
|
64
|
+
this.uploads.set(id, upload);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
UploadRegistry.unregister = function (upload) {
|
|
68
|
+
var id = upload.getId();
|
|
69
|
+
if (id) {
|
|
70
|
+
this.uploads.delete(id);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
UploadRegistry.getById = function (id) {
|
|
74
|
+
return this.uploads.get(id);
|
|
75
|
+
};
|
|
76
|
+
UploadRegistry.has = function (id) {
|
|
77
|
+
return this.uploads.has(id);
|
|
78
|
+
};
|
|
79
|
+
UploadRegistry.clear = function () {
|
|
80
|
+
this.uploads.clear();
|
|
81
|
+
};
|
|
82
|
+
UploadRegistry.uploads = new Map();
|
|
83
|
+
return UploadRegistry;
|
|
84
|
+
}());
|
|
85
|
+
var Upload = /** @class */ (function () {
|
|
86
|
+
function Upload(config) {
|
|
87
|
+
this.uploadId = null;
|
|
88
|
+
this.subscriptions = [];
|
|
89
|
+
this.status = UploadState.Pending;
|
|
90
|
+
this.startPromise = null;
|
|
91
|
+
this.resolveStart = null;
|
|
92
|
+
this.rejectStart = null;
|
|
93
|
+
this.changeCallback = null;
|
|
94
|
+
this.config = config;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Create a new upload instance or return existing one for the same path
|
|
98
|
+
*/
|
|
99
|
+
Upload.create = function (config) {
|
|
100
|
+
// Check if there's an existing upload for this upload id
|
|
101
|
+
var existingUpload = config.customUploadId
|
|
102
|
+
? UploadRegistry.getById(config.customUploadId)
|
|
103
|
+
: null;
|
|
104
|
+
if (existingUpload && existingUpload.isRunning()) {
|
|
105
|
+
console.warn("Upload already in progress for path: ".concat(config.path, ". Returning existing upload."));
|
|
106
|
+
return existingUpload;
|
|
107
|
+
}
|
|
108
|
+
var upload = new Upload(config);
|
|
109
|
+
return upload;
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Resume an existing upload by ID (useful after app restart)
|
|
113
|
+
*/
|
|
114
|
+
Upload.resume = function (uploadId) {
|
|
115
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
116
|
+
var existingUpload, nativeUploads, uploadInfo, upload;
|
|
117
|
+
return __generator(this, function (_a) {
|
|
118
|
+
switch (_a.label) {
|
|
119
|
+
case 0:
|
|
120
|
+
existingUpload = UploadRegistry.getById(uploadId);
|
|
121
|
+
if (existingUpload) {
|
|
122
|
+
return [2 /*return*/, existingUpload];
|
|
123
|
+
}
|
|
124
|
+
return [4 /*yield*/, getAllUploads()];
|
|
125
|
+
case 1:
|
|
126
|
+
nativeUploads = _a.sent();
|
|
127
|
+
uploadInfo = nativeUploads.find(function (u) { return u.id === uploadId; });
|
|
128
|
+
if (!uploadInfo) {
|
|
129
|
+
return [2 /*return*/, null];
|
|
130
|
+
}
|
|
131
|
+
upload = new Upload({ url: '', path: '' });
|
|
132
|
+
upload.uploadId = uploadId;
|
|
133
|
+
upload.status = upload.mapNativeStateToStatus(uploadInfo.state);
|
|
134
|
+
// Register and setup listeners
|
|
135
|
+
UploadRegistry.register(upload);
|
|
136
|
+
upload.setupEventListeners();
|
|
137
|
+
return [2 /*return*/, upload];
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Get all currently tracked uploads
|
|
144
|
+
*/
|
|
145
|
+
Upload.getAll = function () {
|
|
146
|
+
var uploads = [];
|
|
147
|
+
UploadRegistry.uploads.forEach(function (upload) { return uploads.push(upload); });
|
|
148
|
+
return uploads;
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Set a callback to be called whenever the upload state changes
|
|
152
|
+
*/
|
|
153
|
+
Upload.prototype.onChange = function (callback) {
|
|
154
|
+
this.changeCallback = callback;
|
|
155
|
+
return this;
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Start the upload - resolves when upload completes, is cancelled, or errors
|
|
159
|
+
*/
|
|
160
|
+
Upload.prototype.start = function () {
|
|
161
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
162
|
+
var nativeUploads, existingUpload, _a, error_1;
|
|
163
|
+
var _this = this;
|
|
164
|
+
return __generator(this, function (_b) {
|
|
165
|
+
switch (_b.label) {
|
|
166
|
+
case 0:
|
|
167
|
+
if (this.uploadId) {
|
|
168
|
+
throw new Error('Upload already started');
|
|
169
|
+
}
|
|
170
|
+
if (this.startPromise) {
|
|
171
|
+
return [2 /*return*/, this.startPromise];
|
|
172
|
+
}
|
|
173
|
+
if (!this.config.path) return [3 /*break*/, 2];
|
|
174
|
+
return [4 /*yield*/, getAllUploads()];
|
|
175
|
+
case 1:
|
|
176
|
+
nativeUploads = _b.sent();
|
|
177
|
+
existingUpload = nativeUploads.find(function (u) { return u.state === 'running' || u.state === 'pending'; });
|
|
178
|
+
if (existingUpload && !this.config.customUploadId) {
|
|
179
|
+
console.warn("Found existing upload in native side. Resuming upload: ".concat(existingUpload.id));
|
|
180
|
+
this.uploadId = existingUpload.id;
|
|
181
|
+
this.status = this.mapNativeStateToStatus(existingUpload.state);
|
|
182
|
+
UploadRegistry.register(this);
|
|
183
|
+
}
|
|
184
|
+
_b.label = 2;
|
|
185
|
+
case 2:
|
|
186
|
+
this.startPromise = new Promise(function (resolve, reject) {
|
|
187
|
+
_this.resolveStart = resolve;
|
|
188
|
+
_this.rejectStart = reject;
|
|
189
|
+
});
|
|
190
|
+
// Register event listeners
|
|
191
|
+
this.setupEventListeners();
|
|
192
|
+
if (!!this.uploadId) return [3 /*break*/, 6];
|
|
193
|
+
_b.label = 3;
|
|
194
|
+
case 3:
|
|
195
|
+
_b.trys.push([3, 5, , 6]);
|
|
196
|
+
_a = this;
|
|
197
|
+
return [4 /*yield*/, NativeModule.startUpload(this.config)];
|
|
198
|
+
case 4:
|
|
199
|
+
_a.uploadId = _b.sent();
|
|
200
|
+
this.updateStatus(UploadState.Running);
|
|
201
|
+
UploadRegistry.register(this);
|
|
202
|
+
return [3 /*break*/, 6];
|
|
203
|
+
case 5:
|
|
204
|
+
error_1 = _b.sent();
|
|
205
|
+
this.cleanup();
|
|
206
|
+
if (this.rejectStart) {
|
|
207
|
+
this.rejectStart(error_1);
|
|
208
|
+
}
|
|
209
|
+
throw error_1;
|
|
210
|
+
case 6: return [2 /*return*/, this.startPromise];
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
Upload.prototype.setupEventListeners = function () {
|
|
216
|
+
var _this = this;
|
|
217
|
+
// Progress listener
|
|
218
|
+
var progressSubscription = DeviceEventEmitter.addListener(eventPrefix + 'progress', function (data) {
|
|
219
|
+
if (_this.uploadId && data.id === _this.uploadId) {
|
|
220
|
+
_this.notifyChange({
|
|
221
|
+
status: UploadState.Running,
|
|
222
|
+
progress: data.progress,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
this.subscriptions.push(progressSubscription);
|
|
227
|
+
// Completed listener
|
|
228
|
+
var completedSubscription = DeviceEventEmitter.addListener(eventPrefix + 'completed', function (data) {
|
|
229
|
+
if (_this.uploadId && data.id === _this.uploadId) {
|
|
230
|
+
_this.updateStatus(UploadState.Completed, undefined, data.responseCode, data.responseBody);
|
|
231
|
+
if (_this.resolveStart) {
|
|
232
|
+
_this.resolveStart({
|
|
233
|
+
status: 'completed',
|
|
234
|
+
responseCode: data.responseCode,
|
|
235
|
+
responseBody: data.responseBody,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
_this.cleanup();
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
this.subscriptions.push(completedSubscription);
|
|
242
|
+
// Error listener
|
|
243
|
+
var errorSubscription = DeviceEventEmitter.addListener(eventPrefix + 'error', function (data) {
|
|
244
|
+
if (_this.uploadId && data.id === _this.uploadId) {
|
|
245
|
+
_this.updateStatus(UploadState.Error, data.error);
|
|
246
|
+
if (_this.resolveStart) {
|
|
247
|
+
_this.resolveStart({ status: 'error', error: data.error });
|
|
248
|
+
}
|
|
249
|
+
_this.cleanup();
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
this.subscriptions.push(errorSubscription);
|
|
253
|
+
// Cancelled listener
|
|
254
|
+
var cancelledSubscription = DeviceEventEmitter.addListener(eventPrefix + 'cancelled', function (data) {
|
|
255
|
+
if (_this.uploadId && data.id === _this.uploadId) {
|
|
256
|
+
_this.updateStatus(UploadState.Cancelled, data.error);
|
|
257
|
+
if (_this.resolveStart) {
|
|
258
|
+
_this.resolveStart({ status: 'cancelled', error: data.error });
|
|
259
|
+
}
|
|
260
|
+
_this.cleanup();
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
this.subscriptions.push(cancelledSubscription);
|
|
264
|
+
};
|
|
265
|
+
Upload.prototype.updateStatus = function (status, error, responseCode, responseBody) {
|
|
266
|
+
this.status = status;
|
|
267
|
+
this.notifyChange({ status: status, error: error, responseCode: responseCode, responseBody: responseBody });
|
|
268
|
+
};
|
|
269
|
+
Upload.prototype.notifyChange = function (event) {
|
|
270
|
+
if (this.changeCallback) {
|
|
271
|
+
this.changeCallback(event);
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
Upload.prototype.mapNativeStateToStatus = function (state) {
|
|
275
|
+
switch (state) {
|
|
276
|
+
case 'running':
|
|
277
|
+
return UploadState.Running;
|
|
278
|
+
case 'pending':
|
|
279
|
+
return UploadState.Pending;
|
|
280
|
+
case 'cancelled':
|
|
281
|
+
return UploadState.Cancelled;
|
|
282
|
+
case 'completed':
|
|
283
|
+
return UploadState.Completed;
|
|
284
|
+
default:
|
|
285
|
+
return UploadState.Pending;
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
/**
|
|
289
|
+
* Cancel the upload
|
|
290
|
+
*/
|
|
291
|
+
Upload.prototype.cancel = function () {
|
|
292
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
293
|
+
var result, error_2;
|
|
294
|
+
return __generator(this, function (_a) {
|
|
295
|
+
switch (_a.label) {
|
|
296
|
+
case 0:
|
|
297
|
+
if (!this.uploadId) {
|
|
298
|
+
throw new Error('Upload not started');
|
|
299
|
+
}
|
|
300
|
+
_a.label = 1;
|
|
301
|
+
case 1:
|
|
302
|
+
_a.trys.push([1, 3, , 4]);
|
|
303
|
+
return [4 /*yield*/, NativeModule.cancelUpload(this.uploadId)];
|
|
304
|
+
case 2:
|
|
305
|
+
result = _a.sent();
|
|
306
|
+
// Don't cleanup here - let the cancelled event handle it
|
|
307
|
+
return [2 /*return*/, result];
|
|
308
|
+
case 3:
|
|
309
|
+
error_2 = _a.sent();
|
|
310
|
+
this.cleanup();
|
|
311
|
+
throw error_2;
|
|
312
|
+
case 4: return [2 /*return*/];
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
};
|
|
317
|
+
/**
|
|
318
|
+
* Get the current upload status
|
|
319
|
+
*/
|
|
320
|
+
Upload.prototype.getStatus = function () {
|
|
321
|
+
return this.status;
|
|
322
|
+
};
|
|
323
|
+
/**
|
|
324
|
+
* Get the upload ID
|
|
325
|
+
*/
|
|
326
|
+
Upload.prototype.getId = function () {
|
|
327
|
+
return this.uploadId;
|
|
328
|
+
};
|
|
329
|
+
/**
|
|
330
|
+
* Get the file path
|
|
331
|
+
*/
|
|
332
|
+
Upload.prototype.getPath = function () {
|
|
333
|
+
return this.config.path;
|
|
334
|
+
};
|
|
335
|
+
/**
|
|
336
|
+
* Check if upload is in progress
|
|
337
|
+
*/
|
|
338
|
+
Upload.prototype.isRunning = function () {
|
|
339
|
+
return this.status === UploadState.Running;
|
|
340
|
+
};
|
|
341
|
+
/**
|
|
342
|
+
* Clean up listeners
|
|
343
|
+
*/
|
|
344
|
+
Upload.prototype.cleanup = function () {
|
|
345
|
+
this.subscriptions.forEach(function (sub) { return sub.remove(); });
|
|
346
|
+
this.subscriptions = [];
|
|
347
|
+
this.resolveStart = null;
|
|
348
|
+
this.rejectStart = null;
|
|
349
|
+
UploadRegistry.unregister(this);
|
|
350
|
+
};
|
|
351
|
+
return Upload;
|
|
352
|
+
}());
|
|
353
|
+
// Legacy API exports for backward compatibility
|
|
354
|
+
export var getFileInfo = function (path) {
|
|
355
|
+
return NativeModule.getFileInfo(path).then(function (data) {
|
|
356
|
+
if (data.size) {
|
|
357
|
+
data.size = +data.size;
|
|
358
|
+
}
|
|
359
|
+
return data;
|
|
360
|
+
});
|
|
361
|
+
};
|
|
362
|
+
export var startUpload = function (options) {
|
|
363
|
+
return NativeModule.startUpload(options);
|
|
364
|
+
};
|
|
365
|
+
export var cancelUpload = function (cancelUploadId) {
|
|
366
|
+
if (typeof cancelUploadId !== 'string') {
|
|
367
|
+
return Promise.reject(new Error('Upload ID must be a string'));
|
|
368
|
+
}
|
|
369
|
+
return NativeModule.cancelUpload(cancelUploadId);
|
|
370
|
+
};
|
|
371
|
+
export var addListener = function (eventType, uploadId, listener) {
|
|
372
|
+
return DeviceEventEmitter.addListener(eventPrefix + eventType, function (data) {
|
|
373
|
+
if (!uploadId || !data || !('id' in data) || data.id === uploadId) {
|
|
374
|
+
listener(data);
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
};
|
|
378
|
+
export var canSuspendIfBackground = function () {
|
|
379
|
+
if (Platform.OS === 'ios') {
|
|
380
|
+
NativeModule.canSuspendIfBackground();
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
export var shouldLimitNetwork = function (limit) {
|
|
384
|
+
NativeModule.shouldLimitNetwork(limit);
|
|
385
|
+
};
|
|
386
|
+
export var getAllUploads = function () {
|
|
387
|
+
return NativeModule.getAllUploads();
|
|
388
|
+
};
|
|
389
|
+
export { Upload };
|
|
390
|
+
export default Upload;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
#import <MobileCoreServices/MobileCoreServices.h>
|
|
3
|
+
#import <React/RCTEventEmitter.h>
|
|
4
|
+
#import <React/RCTBridgeModule.h>
|
|
5
|
+
|
|
6
|
+
@interface RNFileUploader : RCTEventEmitter <RCTBridgeModule, NSURLSessionTaskDelegate>
|
|
7
|
+
+ (void)setCompletionHandlerWithIdentifier: (NSString *)identifier completionHandler: (void (^)())completionHandler;
|
|
8
|
+
@end
|