@kesha-antonov/react-native-background-downloader 4.5.3 → 4.5.5

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 (34) hide show
  1. package/README.md +74 -8
  2. package/android/build.gradle +4 -2
  3. package/android/src/main/java/com/eko/DownloadConstants.kt +3 -0
  4. package/android/src/main/java/com/eko/Downloader.kt +102 -0
  5. package/android/src/main/java/com/eko/RNBackgroundDownloaderModuleImpl.kt +86 -5
  6. package/android/src/main/java/com/eko/ResumableDownloader.kt +7 -0
  7. package/android/src/main/java/com/eko/UIDTDownloadJobService.kt +42 -4
  8. package/android/src/main/java/com/eko/uidt/UIDTJobManager.kt +11 -1
  9. package/android/src/main/java/com/eko/uidt/UIDTJobState.kt +62 -0
  10. package/android/src/main/java/com/eko/utils/StorageManager.kt +95 -0
  11. package/ios/RNBGDTaskConfig.h +3 -0
  12. package/ios/RNBGDTaskConfig.mm +3 -0
  13. package/ios/RNBackgroundDownloader.mm +375 -48
  14. package/lib/DownloadTask.d.ts +39 -0
  15. package/lib/DownloadTask.js +176 -0
  16. package/lib/NativeRNBackgroundDownloader.d.ts +127 -0
  17. package/lib/NativeRNBackgroundDownloader.js +4 -0
  18. package/lib/UploadTask.d.ts +30 -0
  19. package/lib/UploadTask.js +174 -0
  20. package/lib/config.d.ts +33 -0
  21. package/lib/config.js +79 -0
  22. package/lib/index.d.ts +26 -0
  23. package/lib/index.js +498 -0
  24. package/lib/types.d.ts +249 -0
  25. package/lib/types.js +2 -0
  26. package/package.json +7 -4
  27. package/plugin/build/index.d.ts +2 -2
  28. package/plugin/build/index.js +1 -1
  29. package/react-native-background-downloader.podspec +8 -2
  30. package/src/DownloadTask.ts +2 -0
  31. package/src/NativeRNBackgroundDownloader.ts +2 -0
  32. package/src/config.ts +6 -1
  33. package/src/index.ts +4 -0
  34. package/src/types.ts +27 -0
package/lib/index.js ADDED
@@ -0,0 +1,498 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.directories = exports.getExistingUploadTasks = exports.completeHandler = exports.getExistingDownloadTasks = void 0;
4
+ exports.cleanup = cleanup;
5
+ exports.setConfig = setConfig;
6
+ exports.createDownloadTask = createDownloadTask;
7
+ exports.createUploadTask = createUploadTask;
8
+ exports.getNativeModule = getNativeModule;
9
+ const react_native_1 = require("react-native");
10
+ const DownloadTask_1 = require("./DownloadTask");
11
+ const UploadTask_1 = require("./UploadTask");
12
+ const config_1 = require("./config");
13
+ // Lazy initialization state
14
+ let RNBackgroundDownloader = null;
15
+ let turboModule = null;
16
+ let isIOSNewArchitecture = false;
17
+ let isInitialized = false;
18
+ /**
19
+ * Lazily initialize the native module.
20
+ * This is called on first actual use of the module, not at import time.
21
+ * This prevents issues with module loading before React Native's bridge is ready.
22
+ */
23
+ function ensureNativeModuleInitialized() {
24
+ if (isInitialized && RNBackgroundDownloader != null)
25
+ return RNBackgroundDownloader;
26
+ // Try TurboModules first
27
+ turboModule = react_native_1.TurboModuleRegistry.get('RNBackgroundDownloader');
28
+ // Check if iOS new architecture event emitters are available
29
+ // On Android, we always use NativeEventEmitter because Android uses RCTDeviceEventEmitter
30
+ isIOSNewArchitecture = react_native_1.Platform.OS === 'ios' && turboModule != null && typeof turboModule.onDownloadBegin === 'function';
31
+ if (isIOSNewArchitecture && turboModule) {
32
+ // New architecture: TurboModules use getConstants() method
33
+ const constants = turboModule.getConstants();
34
+ RNBackgroundDownloader = Object.assign(turboModule, constants);
35
+ }
36
+ else {
37
+ // Fall back to old architecture - must use NativeModules for proper event emission
38
+ RNBackgroundDownloader = react_native_1.NativeModules.RNBackgroundDownloader;
39
+ // For old architecture, constants may need to be fetched via getConstants() as well
40
+ if (RNBackgroundDownloader && !RNBackgroundDownloader.documents && typeof RNBackgroundDownloader.getConstants === 'function') {
41
+ const constants = RNBackgroundDownloader.getConstants();
42
+ if (constants)
43
+ Object.assign(RNBackgroundDownloader, constants);
44
+ }
45
+ }
46
+ if (!RNBackgroundDownloader)
47
+ throw new Error('The package \'@kesha-antonov/react-native-background-downloader\' doesn\'t seem to be linked. Make sure: \n\n' +
48
+ react_native_1.Platform.select({ ios: '- You have run \'pod install\'\n', default: '' }) +
49
+ '- You rebuilt the app after installing the package\n' +
50
+ '- You are not using Expo Go\n');
51
+ isInitialized = true;
52
+ // Initialize event listeners after native module is ready
53
+ initializeEventListeners();
54
+ return RNBackgroundDownloader;
55
+ }
56
+ const MIN_PROGRESS_INTERVAL = 250;
57
+ const tasksMap = new Map();
58
+ const uploadTasksMap = new Map();
59
+ // Set up event listeners based on architecture
60
+ // For old architecture, we need to defer NativeEventEmitter creation
61
+ // to avoid issues during module initialization
62
+ let eventListenersInitialized = false;
63
+ let eventSubscriptions = [];
64
+ /**
65
+ * Clean up event listeners. Call this before hot reload or module invalidation.
66
+ * This prevents memory leaks from accumulated event listeners.
67
+ */
68
+ function cleanup() {
69
+ for (const subscription of eventSubscriptions)
70
+ subscription.remove();
71
+ eventSubscriptions = [];
72
+ eventListenersInitialized = false;
73
+ isInitialized = false;
74
+ // Clear module references to allow proper re-initialization
75
+ RNBackgroundDownloader = null;
76
+ turboModule = null;
77
+ isIOSNewArchitecture = false;
78
+ tasksMap.clear();
79
+ uploadTasksMap.clear();
80
+ }
81
+ function initializeEventListeners() {
82
+ var _a, _b, _c, _d;
83
+ if (eventListenersInitialized)
84
+ return;
85
+ eventListenersInitialized = true;
86
+ if (isIOSNewArchitecture && turboModule) {
87
+ // iOS new architecture: use EventEmitter from TurboModule spec
88
+ turboModule.onDownloadBegin((data) => {
89
+ const { id, ...rest } = data;
90
+ (0, config_1.log)('downloadBegin', id, rest);
91
+ const task = tasksMap.get(id);
92
+ if (!task) {
93
+ (0, config_1.log)('downloadBegin: task not found in tasksMap', id);
94
+ return;
95
+ }
96
+ task.onBegin(rest);
97
+ });
98
+ turboModule.onDownloadProgress((events) => {
99
+ (0, config_1.log)('downloadProgress', events);
100
+ for (const event of events) {
101
+ const { id, ...rest } = event;
102
+ const task = tasksMap.get(id);
103
+ if (task)
104
+ task.onProgress(rest);
105
+ }
106
+ });
107
+ turboModule.onDownloadComplete((data) => {
108
+ const { id, ...rest } = data;
109
+ (0, config_1.log)('downloadComplete', id, rest);
110
+ const task = tasksMap.get(id);
111
+ if (!task)
112
+ (0, config_1.log)('downloadComplete: task not found in tasksMap', id);
113
+ else
114
+ task.onDone(rest);
115
+ tasksMap.delete(id);
116
+ });
117
+ turboModule.onDownloadFailed((data) => {
118
+ const { id, ...rest } = data;
119
+ (0, config_1.log)('downloadFailed', id, rest);
120
+ const task = tasksMap.get(id);
121
+ if (!task)
122
+ (0, config_1.log)('downloadFailed: task not found in tasksMap', id);
123
+ else
124
+ task.onError(rest);
125
+ tasksMap.delete(id);
126
+ });
127
+ // Upload events for new architecture (optional - may not exist in all versions)
128
+ if (typeof turboModule.onUploadBegin === 'function') {
129
+ (_a = turboModule.onUploadBegin) === null || _a === void 0 ? void 0 : _a.call(turboModule, (data) => {
130
+ const { id, ...rest } = data;
131
+ (0, config_1.log)('uploadBegin', id, rest);
132
+ const task = uploadTasksMap.get(id);
133
+ if (!task) {
134
+ (0, config_1.log)('uploadBegin: task not found in uploadTasksMap', id);
135
+ return;
136
+ }
137
+ task.onBegin(rest);
138
+ });
139
+ (_b = turboModule.onUploadProgress) === null || _b === void 0 ? void 0 : _b.call(turboModule, (events) => {
140
+ (0, config_1.log)('uploadProgress', events);
141
+ for (const event of events) {
142
+ const { id, ...rest } = event;
143
+ const task = uploadTasksMap.get(id);
144
+ if (task)
145
+ task.onProgress(rest);
146
+ }
147
+ });
148
+ (_c = turboModule.onUploadComplete) === null || _c === void 0 ? void 0 : _c.call(turboModule, (data) => {
149
+ const { id, ...rest } = data;
150
+ (0, config_1.log)('uploadComplete', id, rest);
151
+ const task = uploadTasksMap.get(id);
152
+ if (!task)
153
+ (0, config_1.log)('uploadComplete: task not found in uploadTasksMap', id);
154
+ else
155
+ task.onDone(rest);
156
+ uploadTasksMap.delete(id);
157
+ });
158
+ (_d = turboModule.onUploadFailed) === null || _d === void 0 ? void 0 : _d.call(turboModule, (data) => {
159
+ const { id, ...rest } = data;
160
+ (0, config_1.log)('uploadFailed', id, rest);
161
+ const task = uploadTasksMap.get(id);
162
+ if (!task)
163
+ (0, config_1.log)('uploadFailed: task not found in uploadTasksMap', id);
164
+ else
165
+ task.onError(rest);
166
+ uploadTasksMap.delete(id);
167
+ });
168
+ }
169
+ }
170
+ else {
171
+ // Old architecture: use NativeEventEmitter with the native module
172
+ // RCTEventEmitter on native side requires NativeEventEmitter on JS side
173
+ // RNBackgroundDownloader is guaranteed to be non-null here since initializeEventListeners
174
+ // is only called after ensureNativeModuleInitialized() succeeds
175
+ const eventEmitter = new react_native_1.NativeEventEmitter(RNBackgroundDownloader);
176
+ eventSubscriptions.push(eventEmitter.addListener('downloadBegin', (data) => {
177
+ const { id, ...rest } = data;
178
+ (0, config_1.log)('downloadBegin', id, rest);
179
+ const task = tasksMap.get(id);
180
+ if (!task) {
181
+ (0, config_1.log)('downloadBegin: task not found in tasksMap', id);
182
+ return;
183
+ }
184
+ task.onBegin(rest);
185
+ }));
186
+ eventSubscriptions.push(eventEmitter.addListener('downloadProgress', (events) => {
187
+ (0, config_1.log)('downloadProgress', events);
188
+ for (const event of events) {
189
+ const { id, ...rest } = event;
190
+ const task = tasksMap.get(id);
191
+ if (task)
192
+ task.onProgress(rest);
193
+ }
194
+ }));
195
+ eventSubscriptions.push(eventEmitter.addListener('downloadComplete', (data) => {
196
+ const { id, ...rest } = data;
197
+ (0, config_1.log)('downloadComplete', id, rest);
198
+ const task = tasksMap.get(id);
199
+ if (!task)
200
+ (0, config_1.log)('downloadComplete: task not found in tasksMap', id);
201
+ else
202
+ task.onDone(rest);
203
+ tasksMap.delete(id);
204
+ }));
205
+ eventSubscriptions.push(eventEmitter.addListener('downloadFailed', (data) => {
206
+ const { id, ...rest } = data;
207
+ (0, config_1.log)('downloadFailed', id, rest);
208
+ const task = tasksMap.get(id);
209
+ if (!task)
210
+ (0, config_1.log)('downloadFailed: task not found in tasksMap', id);
211
+ else
212
+ task.onError(rest);
213
+ tasksMap.delete(id);
214
+ }));
215
+ // Upload events for old architecture
216
+ eventSubscriptions.push(eventEmitter.addListener('uploadBegin', (data) => {
217
+ const { id, ...rest } = data;
218
+ (0, config_1.log)('uploadBegin', id, rest);
219
+ const task = uploadTasksMap.get(id);
220
+ if (!task) {
221
+ (0, config_1.log)('uploadBegin: task not found in uploadTasksMap', id);
222
+ return;
223
+ }
224
+ task.onBegin(rest);
225
+ }));
226
+ eventSubscriptions.push(eventEmitter.addListener('uploadProgress', (events) => {
227
+ (0, config_1.log)('uploadProgress', events);
228
+ for (const event of events) {
229
+ const { id, ...rest } = event;
230
+ const task = uploadTasksMap.get(id);
231
+ if (task)
232
+ task.onProgress(rest);
233
+ }
234
+ }));
235
+ eventSubscriptions.push(eventEmitter.addListener('uploadComplete', (data) => {
236
+ const { id, ...rest } = data;
237
+ (0, config_1.log)('uploadComplete', id, rest);
238
+ const task = uploadTasksMap.get(id);
239
+ if (!task)
240
+ (0, config_1.log)('uploadComplete: task not found in uploadTasksMap', id);
241
+ else
242
+ task.onDone(rest);
243
+ uploadTasksMap.delete(id);
244
+ }));
245
+ eventSubscriptions.push(eventEmitter.addListener('uploadFailed', (data) => {
246
+ const { id, ...rest } = data;
247
+ (0, config_1.log)('uploadFailed', id, rest);
248
+ const task = uploadTasksMap.get(id);
249
+ if (!task)
250
+ (0, config_1.log)('uploadFailed: task not found in uploadTasksMap', id);
251
+ else
252
+ task.onError(rest);
253
+ uploadTasksMap.delete(id);
254
+ }));
255
+ // Native debug log events - forward native iOS logs to JS logCallback
256
+ eventSubscriptions.push(eventEmitter.addListener('nativeDebugLog', (data) => {
257
+ (0, config_1.log)('[Native]', data.taskId || '', data.message);
258
+ }));
259
+ }
260
+ }
261
+ // Event listeners are now initialized lazily when ensureNativeModuleInitialized() is called
262
+ // This ensures the bridge is ready before any native module access
263
+ function setConfig({ headers = {}, progressInterval = config_1.DEFAULT_PROGRESS_INTERVAL, progressMinBytes = config_1.DEFAULT_PROGRESS_MIN_BYTES, isLogsEnabled = false, logCallback, maxParallelDownloads, allowsCellularAccess, showNotificationsEnabled, notificationsGrouping, iosDataProtection, }) {
264
+ var _a, _b, _c;
265
+ config_1.config.headers = headers;
266
+ if (iosDataProtection !== undefined)
267
+ config_1.config.iosDataProtection = iosDataProtection;
268
+ if (progressInterval >= MIN_PROGRESS_INTERVAL)
269
+ config_1.config.progressInterval = progressInterval;
270
+ else
271
+ console.warn(`[RNBackgroundDownloader] progressInterval must be a number >= ${MIN_PROGRESS_INTERVAL}. You passed ${progressInterval}`);
272
+ if (progressMinBytes >= 0)
273
+ config_1.config.progressMinBytes = progressMinBytes;
274
+ else
275
+ console.warn(`[RNBackgroundDownloader] progressMinBytes must be a number >= 0. You passed ${progressMinBytes}`);
276
+ if (maxParallelDownloads !== undefined)
277
+ if (maxParallelDownloads >= 1)
278
+ config_1.config.maxParallelDownloads = maxParallelDownloads;
279
+ else
280
+ console.warn(`[RNBackgroundDownloader] maxParallelDownloads must be a number >= 1. You passed ${maxParallelDownloads}`);
281
+ if (allowsCellularAccess !== undefined)
282
+ config_1.config.allowsCellularAccess = allowsCellularAccess;
283
+ // Update showNotificationsEnabled
284
+ if (showNotificationsEnabled !== undefined)
285
+ config_1.config.showNotificationsEnabled = showNotificationsEnabled;
286
+ // Update notification grouping config
287
+ if (notificationsGrouping !== undefined)
288
+ config_1.config.notificationsGrouping = {
289
+ enabled: (_a = notificationsGrouping.enabled) !== null && _a !== void 0 ? _a : false,
290
+ mode: (_b = notificationsGrouping.mode) !== null && _b !== void 0 ? _b : 'individual',
291
+ texts: {
292
+ ...config_1.DEFAULT_NOTIFICATION_TEXTS,
293
+ ...notificationsGrouping.texts,
294
+ },
295
+ };
296
+ config_1.config.isLogsEnabled = isLogsEnabled;
297
+ config_1.config.logCallback = logCallback;
298
+ // Notify native side about configuration changes
299
+ try {
300
+ const nativeModule = ensureNativeModuleInitialized();
301
+ if (nativeModule.setLogsEnabled)
302
+ nativeModule.setLogsEnabled(isLogsEnabled);
303
+ // Only call native methods if config was successfully updated
304
+ if (nativeModule.setMaxParallelDownloads && maxParallelDownloads !== undefined && maxParallelDownloads >= 1)
305
+ nativeModule.setMaxParallelDownloads(config_1.config.maxParallelDownloads);
306
+ if (nativeModule.setAllowsCellularAccess && allowsCellularAccess !== undefined)
307
+ nativeModule.setAllowsCellularAccess(config_1.config.allowsCellularAccess);
308
+ // Update notification config on native side (Android)
309
+ if (react_native_1.Platform.OS === 'android' && nativeModule.setNotificationGroupingConfig)
310
+ nativeModule.setNotificationGroupingConfig({
311
+ enabled: config_1.config.notificationsGrouping.enabled,
312
+ showNotificationsEnabled: (_c = config_1.config.showNotificationsEnabled) !== null && _c !== void 0 ? _c : false,
313
+ mode: config_1.config.notificationsGrouping.mode,
314
+ texts: (0, config_1.getNotificationTextsForNative)(),
315
+ });
316
+ }
317
+ catch {
318
+ // Ignore if native module is not available yet
319
+ }
320
+ }
321
+ const getExistingDownloadTasks = async () => {
322
+ const nativeModule = ensureNativeModuleInitialized();
323
+ const downloads = await nativeModule.getExistingDownloadTasks();
324
+ const downloadTasks = downloads.map(downloadInfo => {
325
+ var _a;
326
+ // Parse metadata from JSON string to object
327
+ let metadata = {};
328
+ if (downloadInfo.metadata)
329
+ try {
330
+ metadata = JSON.parse(downloadInfo.metadata);
331
+ }
332
+ catch {
333
+ // Keep empty object if parsing fails
334
+ }
335
+ const taskInfo = {
336
+ ...downloadInfo,
337
+ metadata,
338
+ errorCode: (_a = downloadInfo.errorCode) !== null && _a !== void 0 ? _a : 0,
339
+ };
340
+ // second argument re-assigns event handlers
341
+ const task = new DownloadTask_1.DownloadTask(taskInfo, tasksMap.get(taskInfo.id));
342
+ switch (taskInfo.state) {
343
+ case nativeModule.TaskRunning: {
344
+ task.state = 'DOWNLOADING';
345
+ break;
346
+ }
347
+ case nativeModule.TaskSuspended: {
348
+ task.state = 'PAUSED';
349
+ break;
350
+ }
351
+ case nativeModule.TaskCanceling: {
352
+ // On iOS, paused tasks (via cancelByProducingResumeData) are in Canceling state with errorCode -999
353
+ if (taskInfo.errorCode === -999) {
354
+ task.state = 'PAUSED';
355
+ }
356
+ else {
357
+ task.stop();
358
+ return undefined;
359
+ }
360
+ break;
361
+ }
362
+ case nativeModule.TaskCompleted: {
363
+ if (taskInfo.bytesDownloaded === taskInfo.bytesTotal)
364
+ task.state = 'DONE';
365
+ else
366
+ // IOS completed the download but it was not done.
367
+ return undefined;
368
+ }
369
+ }
370
+ return task;
371
+ }).filter((task) => task !== undefined);
372
+ for (const task of downloadTasks)
373
+ tasksMap.set(task.id, task);
374
+ return downloadTasks;
375
+ };
376
+ exports.getExistingDownloadTasks = getExistingDownloadTasks;
377
+ const completeHandler = (jobId) => {
378
+ if (jobId == null) {
379
+ (0, config_1.log)('completeHandler: jobId is empty');
380
+ return;
381
+ }
382
+ const nativeModule = ensureNativeModuleInitialized();
383
+ return nativeModule.completeHandler(jobId);
384
+ };
385
+ exports.completeHandler = completeHandler;
386
+ function createDownloadTask({ isAllowedOverRoaming = true, isAllowedOverMetered = true, metadata, ...rest }) {
387
+ // Ensure native module and event listeners are initialized before creating tasks
388
+ ensureNativeModuleInitialized();
389
+ if (!rest.id || !rest.url || !rest.destination)
390
+ throw new Error('[RNBackgroundDownloader] id, url and destination are required');
391
+ rest.headers = { ...config_1.config.headers, ...rest.headers };
392
+ rest.destination = rest.destination.replace('file://', '');
393
+ const task = new DownloadTask_1.DownloadTask({
394
+ id: rest.id,
395
+ metadata,
396
+ });
397
+ task.setDownloadParams({
398
+ isAllowedOverRoaming,
399
+ isAllowedOverMetered,
400
+ ...rest,
401
+ });
402
+ tasksMap.set(rest.id, task);
403
+ return task;
404
+ }
405
+ const getExistingUploadTasks = async () => {
406
+ const nativeModule = ensureNativeModuleInitialized();
407
+ if (!nativeModule.getExistingUploadTasks) {
408
+ (0, config_1.log)('getExistingUploadTasks: not supported - native implementation missing');
409
+ return [];
410
+ }
411
+ const uploads = await nativeModule.getExistingUploadTasks();
412
+ const uploadTasks = uploads.map(uploadInfo => {
413
+ var _a;
414
+ // Parse metadata from JSON string to object
415
+ let metadata = {};
416
+ if (uploadInfo.metadata)
417
+ try {
418
+ metadata = JSON.parse(uploadInfo.metadata);
419
+ }
420
+ catch {
421
+ // Keep empty object if parsing fails
422
+ }
423
+ const taskInfo = {
424
+ ...uploadInfo,
425
+ metadata,
426
+ errorCode: (_a = uploadInfo.errorCode) !== null && _a !== void 0 ? _a : 0,
427
+ };
428
+ // second argument re-assigns event handlers
429
+ const task = new UploadTask_1.UploadTask(taskInfo, uploadTasksMap.get(taskInfo.id));
430
+ switch (taskInfo.state) {
431
+ case nativeModule.TaskRunning: {
432
+ task.state = 'UPLOADING';
433
+ break;
434
+ }
435
+ case nativeModule.TaskSuspended: {
436
+ task.state = 'PAUSED';
437
+ break;
438
+ }
439
+ case nativeModule.TaskCanceling: {
440
+ // On iOS, paused tasks (via cancelByProducingResumeData) are in Canceling state with errorCode -999
441
+ if (taskInfo.errorCode === -999) {
442
+ task.state = 'PAUSED';
443
+ }
444
+ else {
445
+ task.stop();
446
+ return undefined;
447
+ }
448
+ break;
449
+ }
450
+ case nativeModule.TaskCompleted: {
451
+ if (taskInfo.bytesUploaded === taskInfo.bytesTotal)
452
+ task.state = 'DONE';
453
+ else
454
+ // IOS completed the upload but it was not done.
455
+ return undefined;
456
+ }
457
+ }
458
+ return task;
459
+ }).filter((task) => task !== undefined);
460
+ for (const task of uploadTasks)
461
+ uploadTasksMap.set(task.id, task);
462
+ return uploadTasks;
463
+ };
464
+ exports.getExistingUploadTasks = getExistingUploadTasks;
465
+ function createUploadTask({ isAllowedOverRoaming = true, isAllowedOverMetered = true, metadata, ...rest }) {
466
+ // Ensure native module and event listeners are initialized before creating tasks
467
+ ensureNativeModuleInitialized();
468
+ if (!rest.id || !rest.url || !rest.source)
469
+ throw new Error('[RNBackgroundDownloader] id, url and source are required');
470
+ rest.headers = { ...config_1.config.headers, ...rest.headers };
471
+ rest.source = rest.source.replace('file://', '');
472
+ const task = new UploadTask_1.UploadTask({
473
+ id: rest.id,
474
+ metadata,
475
+ });
476
+ task.setUploadParams({
477
+ isAllowedOverRoaming,
478
+ isAllowedOverMetered,
479
+ ...rest,
480
+ });
481
+ uploadTasksMap.set(rest.id, task);
482
+ return task;
483
+ }
484
+ // Use getter to lazily initialize native module when directories are accessed
485
+ exports.directories = {
486
+ get documents() {
487
+ return ensureNativeModuleInitialized().documents;
488
+ },
489
+ };
490
+ /**
491
+ * Get the native module instance.
492
+ * This is exported for internal use by DownloadTask to avoid duplicating
493
+ * the TurboModule/NativeModule lookup logic.
494
+ * @internal
495
+ */
496
+ function getNativeModule() {
497
+ return ensureNativeModuleInitialized();
498
+ }