react-native-blob-util 0.22.0 → 0.22.2

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 (97) hide show
  1. package/.eslintrc.js +56 -56
  2. package/LICENSE +21 -21
  3. package/Migration.md +41 -41
  4. package/NuGet.config +11 -11
  5. package/README.md +1109 -1104
  6. package/android/gradle.properties +1 -1
  7. package/android/src/main/AndroidManifest.xml +37 -37
  8. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilConfig.java +57 -57
  9. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilConst.java +20 -20
  10. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFileTransformer.java +9 -9
  11. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilImpl.java +431 -431
  12. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilProgressConfig.java +39 -39
  13. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java +1014 -1014
  14. package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilDefaultResp.java +98 -98
  15. package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilFileResp.java +166 -166
  16. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/FileDescription.java +19 -19
  17. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/FileProvider.java +4 -4
  18. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/MimeType.java +70 -70
  19. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/PathResolver.java +223 -223
  20. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/Tls12SocketFactory.java +68 -68
  21. package/android/src/main/res/values/strings.xml +3 -3
  22. package/android/src/main/res/xml/provider_paths.xml +12 -12
  23. package/android.js +58 -58
  24. package/class/ReactNativeBlobUtilCanceledFetchError.js +9 -9
  25. package/class/ReactNativeBlobUtilFile.js +5 -5
  26. package/class/ReactNativeBlobUtilReadStream.js +84 -84
  27. package/class/ReactNativeBlobUtilSession.js +68 -68
  28. package/class/ReactNativeBlobUtilWriteStream.js +50 -50
  29. package/class/StatefulPromise.js +7 -7
  30. package/codegenSpecs/NativeBlobUtils.js +86 -86
  31. package/components/Fetch.onPress.js +10 -10
  32. package/components/Fetch.when.js +15 -15
  33. package/fetch.js +350 -350
  34. package/fs.js +480 -480
  35. package/index.js +64 -64
  36. package/index.js.flow +192 -192
  37. package/index.web.js +1 -1
  38. package/ios/PrivacyInfo.xcprivacy +28 -28
  39. package/ios/ReactNativeBlobUtil/ReactNativeBlobUtil.h +55 -55
  40. package/ios/ReactNativeBlobUtil/ReactNativeBlobUtil.mm +992 -992
  41. package/ios/ReactNativeBlobUtil.xcodeproj/project.pbxproj +405 -405
  42. package/ios/ReactNativeBlobUtilConst.h +58 -58
  43. package/ios/ReactNativeBlobUtilConst.mm +47 -47
  44. package/ios/ReactNativeBlobUtilFS.h +108 -108
  45. package/ios/ReactNativeBlobUtilFS.mm +1064 -1064
  46. package/ios/ReactNativeBlobUtilFileTransformer.h +23 -23
  47. package/ios/ReactNativeBlobUtilFileTransformer.mm +20 -20
  48. package/ios/ReactNativeBlobUtilNetwork.h +49 -49
  49. package/ios/ReactNativeBlobUtilNetwork.mm +159 -159
  50. package/ios/ReactNativeBlobUtilProgress.h +32 -32
  51. package/ios/ReactNativeBlobUtilProgress.mm +57 -57
  52. package/ios/ReactNativeBlobUtilReqBuilder.h +37 -37
  53. package/ios/ReactNativeBlobUtilReqBuilder.mm +292 -292
  54. package/ios/ReactNativeBlobUtilRequest.h +48 -48
  55. package/ios/ReactNativeBlobUtilRequest.mm +584 -584
  56. package/ios.js +61 -61
  57. package/json-stream.js +42 -42
  58. package/lib/oboe-browser.js +2703 -2703
  59. package/mediacollection.js +36 -36
  60. package/package.json +68 -68
  61. package/polyfill/Blob.js +362 -362
  62. package/polyfill/Event.js +11 -11
  63. package/polyfill/EventTarget.js +78 -78
  64. package/polyfill/Fetch.js +219 -219
  65. package/polyfill/File.js +27 -27
  66. package/polyfill/FileReader.js +91 -91
  67. package/polyfill/ProgressEvent.js +32 -32
  68. package/polyfill/XMLHttpRequest.js +466 -466
  69. package/polyfill/XMLHttpRequestEventTarget.js +126 -126
  70. package/polyfill/index.js +11 -11
  71. package/react-native-blob-util.podspec +48 -48
  72. package/types.js +69 -69
  73. package/utils/log.js +40 -40
  74. package/utils/unicode.js +7 -7
  75. package/utils/uri.js +33 -33
  76. package/utils/uuid.js +4 -4
  77. package/windows/ExperimentalFeatures.props +33 -33
  78. package/windows/README.md +2 -2
  79. package/windows/ReactNativeBlobUtil/PropertySheet.props +15 -15
  80. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.cpp +1836 -1836
  81. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.def +3 -3
  82. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.h +372 -372
  83. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.vcxproj +139 -139
  84. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.vcxproj.filters +43 -43
  85. package/windows/ReactNativeBlobUtil/ReactPackageProvider.cpp +20 -20
  86. package/windows/ReactNativeBlobUtil/ReactPackageProvider.h +24 -24
  87. package/windows/ReactNativeBlobUtil/ReactPackageProvider.idl +9 -9
  88. package/windows/ReactNativeBlobUtil/codegen/.clang-format +1 -1
  89. package/windows/ReactNativeBlobUtil/codegen/NativeBlobUtilsDataTypes.g.h +42 -42
  90. package/windows/ReactNativeBlobUtil/codegen/NativeBlobUtilsSpec.g.h +353 -353
  91. package/windows/ReactNativeBlobUtil/packages.config +3 -3
  92. package/windows/ReactNativeBlobUtil/packages.lock.json +59 -59
  93. package/windows/ReactNativeBlobUtil/pch.cpp +1 -1
  94. package/windows/ReactNativeBlobUtil/pch.h +30 -30
  95. package/windows/ReactNativeBlobUtil/resource.h +5 -5
  96. package/windows/ReactNativeBlobUtil/targetver.h +8 -8
  97. package/windows/ReactNativeBlobUtil.sln +43 -43
package/fetch.js CHANGED
@@ -1,350 +1,350 @@
1
- import {ReactNativeBlobUtilConfig} from './types';
2
- import URIUtil from './utils/uri';
3
- import fs from './fs';
4
- import getUUID from './utils/uuid';
5
- import {NativeEventEmitter} from 'react-native';
6
- import {FetchBlobResponse} from './class/ReactNativeBlobUtilBlobResponse';
7
- import CanceledFetchError from './class/ReactNativeBlobUtilCanceledFetchError';
8
- import ReactNativeBlobUtil from './codegenSpecs/NativeBlobUtils';
9
-
10
- const eventEmitter = new NativeEventEmitter(ReactNativeBlobUtil);
11
-
12
- // register message channel event handler.
13
- eventEmitter.addListener('ReactNativeBlobUtilMessage', (e) => {
14
- if (typeof e === 'string') e = JSON.parse(e);
15
-
16
- if (e.event === 'warn') {
17
- console.warn(e.detail);
18
- }
19
- else if (e.event === 'error') {
20
- throw e.detail;
21
- }
22
- else {
23
- console.log('ReactNativeBlobUtil native message', e.detail);
24
- }
25
- });
26
-
27
- /**
28
- * Calling this method will inject configurations into followed `fetch` method.
29
- * @param {ReactNativeBlobUtilConfig} options
30
- * Fetch API configurations, contains the following options :
31
- * @property {boolean} fileCache
32
- * When fileCache is `true`, response data will be saved in
33
- * storage with a random generated file name, rather than
34
- * a BASE64 encoded string.
35
- * @property {string} appendExt
36
- * Set this property to change file extension of random-
37
- * generated file name.
38
- * @property {string} path
39
- * If this property has a valid string format, resonse data
40
- * will be saved to specific file path. Default string format
41
- * is : `ReactNativeBlobUtil-file://path-to-file`
42
- * @property {string} key
43
- * If this property is set, it will be converted to md5, to
44
- * check if a file with this name exists.
45
- * If it exists, the absolute path is returned (no network
46
- * activity takes place )
47
- * If it doesn't exist, the file is downloaded as usual
48
- * @property {number} timeout
49
- * Request timeout in millionseconds, by default it's 60000ms.
50
- * @property {boolean} followRedirect
51
- * Follow redirects automatically, default true
52
- * @property {boolean} trusty
53
- * Trust all certificates
54
- * @property {boolean} wifiOnly
55
- * Only do requests through WiFi. Android SDK 21 or above only.
56
- *
57
- * @return {function} This method returns a `fetch` method instance.
58
- */
59
- export function config(options: ReactNativeBlobUtilConfig) {
60
- return {fetch: fetch.bind(options)};
61
- }
62
-
63
- /**
64
- * Fetch from file system, use the same interface as RNFB.fetch
65
- * @param {ReactNativeBlobUtilConfig} [options={}] Fetch configurations
66
- * @param {string} method Should be one of `get`, `post`, `put`
67
- * @param {string} url A file URI string
68
- * @param {string} headers Arguments of file system API
69
- * @param {any} body Data to put or post to file systen.
70
- * @return {Promise}
71
- */
72
- function fetchFile(options = {}, method, url, headers = {}, body): Promise {
73
-
74
- if (!URIUtil.isFileURI(url)) {
75
- throw `could not fetch file from an invalid URI : ${url}`;
76
- }
77
-
78
- url = URIUtil.unwrapFileURI(url);
79
-
80
- let promise = null,
81
- cursor = 0,
82
- total = -1,
83
- cacheData = '',
84
- info = null,
85
- _progress, _uploadProgress, _stateChange;
86
-
87
- switch (method.toLowerCase()) {
88
-
89
- case 'post':
90
- break;
91
-
92
- case 'put':
93
- break;
94
-
95
- // read data from file system
96
- default:
97
- promise = fs.stat(url)
98
- .then((stat) => {
99
- total = stat.size;
100
- return fs.readStream(url,
101
- headers.encoding || 'utf8',
102
- Math.floor(headers.bufferSize) || 409600,
103
- Math.floor(headers.interval) || 100
104
- );
105
- })
106
- .then((stream) => new Promise((resolve, reject) => {
107
- stream.open();
108
- info = {
109
- state: '2',
110
- headers: {'source': 'system-fs'},
111
- status: 200,
112
- respType: 'text',
113
- rnfbEncode: headers.encoding || 'utf8'
114
- };
115
- _stateChange(info);
116
- stream.onData((chunk) => {
117
- _progress && _progress(cursor, total, chunk);
118
- if (headers.noCache)
119
- return;
120
- cacheData += chunk;
121
- });
122
- stream.onError((err) => {
123
- reject(err);
124
- });
125
- stream.onEnd(() => {
126
- resolve(new FetchBlobResponse(null, info, cacheData));
127
- });
128
- }));
129
- break;
130
- }
131
-
132
- promise.progress = (fn) => {
133
- _progress = fn;
134
- return promise;
135
- };
136
- promise.stateChange = (fn) => {
137
- _stateChange = fn;
138
- return promise;
139
- };
140
- promise.uploadProgress = (fn) => {
141
- _uploadProgress = fn;
142
- return promise;
143
- };
144
-
145
- return promise;
146
- }
147
-
148
- /**
149
- * Create a HTTP request by settings, the `this` context is a `ReactNativeBlobUtilConfig` object.
150
- * @param {string} method HTTP method, should be `GET`, `POST`, `PUT`, `DELETE`
151
- * @param {string} url Request target url string.
152
- * @param {object} headers HTTP request headers.
153
- * @param {string} body
154
- * Request body, can be either a BASE64 encoded data string,
155
- * or a file path with prefix `ReactNativeBlobUtil-file://` (can be changed)
156
- * @return {Promise}
157
- * This promise instance also contains a Customized method `progress`for
158
- * register progress event handler.
159
- */
160
- export function fetch(...args: any): Promise {
161
-
162
- // create task ID for receiving progress event
163
- let taskId = getUUID();
164
- let options = this || {};
165
- let subscription, subscriptionUpload, stateEvent, partEvent;
166
- let respInfo = {'uninit': true};
167
- let [method, url, headers, body] = [...args];
168
-
169
- // # 241 normalize null or undefined headers, in case nil or null string
170
- // pass to native context
171
- headers = headers && Object.keys(headers).reduce((result, key) => {
172
- result[key] = headers[key] || '';
173
- return result;
174
- }, {});
175
-
176
- // fetch from file system
177
- if (URIUtil.isFileURI(url)) {
178
- return fetchFile(options, method, url, headers, body);
179
- }
180
-
181
- let promiseResolve;
182
- let promiseReject;
183
-
184
- // from remote HTTP(S)
185
- let promise = new Promise((resolve, reject) => {
186
- promiseResolve = resolve;
187
- promiseReject = reject;
188
-
189
- let nativeMethodName = Array.isArray(body) ? 'fetchBlobForm' : 'fetchBlob';
190
-
191
- // on progress event listener
192
- subscription = eventEmitter.addListener('ReactNativeBlobUtilProgress', (e) => {
193
- if (typeof e === 'string') e = JSON.parse(e);
194
- if (e.taskId === taskId && promise.onProgress) {
195
- promise.onProgress(e.written, e.total, e.chunk);
196
- }
197
- });
198
-
199
- subscriptionUpload = eventEmitter.addListener('ReactNativeBlobUtilProgress-upload', (e) => {
200
- if (typeof e === 'string') e = JSON.parse(e);
201
- if (e.taskId === taskId && promise.onUploadProgress) {
202
- promise.onUploadProgress(e.written, e.total);
203
- }
204
- });
205
-
206
- stateEvent = eventEmitter.addListener('ReactNativeBlobUtilState', (e) => {
207
- if (typeof e === 'string') e = JSON.parse(e);
208
- if (e.taskId === taskId)
209
- respInfo = e;
210
- promise.onStateChange && promise.onStateChange(e);
211
- });
212
-
213
- subscription = eventEmitter.addListener('ReactNativeBlobUtilExpire', (e) => {
214
- if (typeof e === 'string') e = JSON.parse(e);
215
- if (e.taskId === taskId && promise.onExpire) {
216
- promise.onExpire(e);
217
- }
218
- });
219
-
220
- partEvent = eventEmitter.addListener('ReactNativeBlobUtilServerPush', (e) => {
221
- if (typeof e === 'string') e = JSON.parse(e);
222
- if (e.taskId === taskId && promise.onPartData) {
223
- promise.onPartData(e.chunk);
224
- }
225
- });
226
-
227
- // When the request body comes from Blob polyfill, we should use special its ref
228
- // as the request body
229
- if (body instanceof Blob && body.isReactNativeBlobUtilPolyfill) {
230
- body = body.getReactNativeBlobUtilRef();
231
- }
232
-
233
- let req = ReactNativeBlobUtil[nativeMethodName];
234
-
235
- /**
236
- * Send request via native module, the response callback accepts three arguments
237
- * @callback
238
- * @param err {any} Error message or object, when the request success, this
239
- * parameter should be `null`.
240
- * @param rawType { 'utf8' | 'base64' | 'path'} RNFB request will be stored
241
- * as UTF8 string, BASE64 string, or a file path reference
242
- * in JS context, and this parameter indicates which one
243
- * dose the response data presents.
244
- * @param data {string} Response data or its reference.
245
- * @param responseInfo {Object.<>}
246
- */
247
- req(options, taskId, method, url, headers || {}, body, (err, rawType, data, responseInfo) => {
248
-
249
- // task done, remove event listeners
250
- subscription.remove();
251
- subscriptionUpload.remove();
252
- stateEvent.remove();
253
- partEvent.remove();
254
- delete promise.progress;
255
- delete promise.uploadProgress;
256
- delete promise.stateChange;
257
- delete promise.part;
258
- delete promise.cancel;
259
- // delete promise['expire']
260
- promise.cancel = () => {
261
- };
262
-
263
- if(!responseInfo) responseInfo = {}; // should not be null / undefined
264
-
265
- if (err)
266
- reject(new Error(err, respInfo));
267
- else {
268
- // response data is saved to storage, create a session for it
269
- if (options.path || options.fileCache || options.addAndroidDownloads
270
- || options.key || options.auto && respInfo.respType === 'blob') {
271
- if (options.session)
272
- fs.session(options.session).add(data);
273
- }
274
- if ('uninit' in respInfo && respInfo.uninit) // event didn't fire yet so we override it here
275
- respInfo = responseInfo;
276
-
277
- respInfo.rnfbEncode = rawType;
278
- resolve(new FetchBlobResponse(taskId, respInfo, data));
279
- }
280
-
281
- });
282
-
283
- });
284
-
285
- // extend Promise object, add `progress`, `uploadProgress`, and `cancel`
286
- // method for register progress event handler and cancel request.
287
- // Add second parameter for performance purpose #140
288
- // When there's only one argument pass to this method, use default `interval`
289
- // and `count`, otherwise use the given on.
290
- // TODO : code refactor, move `uploadProgress` and `progress` to StatefulPromise
291
- promise.progress = (...args) => {
292
- let interval = 250;
293
- let count = -1;
294
- let fn = () => {
295
- };
296
- if (args.length === 2) {
297
- interval = args[0].interval || interval;
298
- count = args[0].count || count;
299
- fn = args[1];
300
- }
301
- else {
302
- fn = args[0];
303
- }
304
- promise.onProgress = fn;
305
- ReactNativeBlobUtil.enableProgressReport(taskId, interval, count);
306
- return promise;
307
- };
308
- promise.uploadProgress = (...args) => {
309
- let interval = 250;
310
- let count = -1;
311
- let fn = () => {
312
- };
313
- if (args.length === 2) {
314
- interval = args[0].interval || interval;
315
- count = args[0].count || count;
316
- fn = args[1];
317
- }
318
- else {
319
- fn = args[0];
320
- }
321
- promise.onUploadProgress = fn;
322
- ReactNativeBlobUtil.enableUploadProgressReport(taskId, interval, count);
323
- return promise;
324
- };
325
- promise.part = (fn) => {
326
- promise.onPartData = fn;
327
- return promise;
328
- };
329
- promise.stateChange = (fn) => {
330
- promise.onStateChange = fn;
331
- return promise;
332
- };
333
- promise.expire = (fn) => {
334
- promise.onExpire = fn;
335
- return promise;
336
- };
337
- promise.cancel = (fn) => {
338
- fn = fn || function () {
339
- };
340
- subscription.remove();
341
- subscriptionUpload.remove();
342
- stateEvent.remove();
343
- ReactNativeBlobUtil.cancelRequest(taskId, fn);
344
- promiseReject(new CanceledFetchError('canceled'));
345
- };
346
- promise.taskId = taskId;
347
-
348
- return promise;
349
-
350
- }
1
+ import {ReactNativeBlobUtilConfig} from './types';
2
+ import URIUtil from './utils/uri';
3
+ import fs from './fs';
4
+ import getUUID from './utils/uuid';
5
+ import {NativeEventEmitter} from 'react-native';
6
+ import {FetchBlobResponse} from './class/ReactNativeBlobUtilBlobResponse';
7
+ import CanceledFetchError from './class/ReactNativeBlobUtilCanceledFetchError';
8
+ import ReactNativeBlobUtil from './codegenSpecs/NativeBlobUtils';
9
+
10
+ const eventEmitter = new NativeEventEmitter(ReactNativeBlobUtil);
11
+
12
+ // register message channel event handler.
13
+ eventEmitter.addListener('ReactNativeBlobUtilMessage', (e) => {
14
+ if (typeof e === 'string') e = JSON.parse(e);
15
+
16
+ if (e.event === 'warn') {
17
+ console.warn(e.detail);
18
+ }
19
+ else if (e.event === 'error') {
20
+ throw e.detail;
21
+ }
22
+ else {
23
+ console.log('ReactNativeBlobUtil native message', e.detail);
24
+ }
25
+ });
26
+
27
+ /**
28
+ * Calling this method will inject configurations into followed `fetch` method.
29
+ * @param {ReactNativeBlobUtilConfig} options
30
+ * Fetch API configurations, contains the following options :
31
+ * @property {boolean} fileCache
32
+ * When fileCache is `true`, response data will be saved in
33
+ * storage with a random generated file name, rather than
34
+ * a BASE64 encoded string.
35
+ * @property {string} appendExt
36
+ * Set this property to change file extension of random-
37
+ * generated file name.
38
+ * @property {string} path
39
+ * If this property has a valid string format, resonse data
40
+ * will be saved to specific file path. Default string format
41
+ * is : `ReactNativeBlobUtil-file://path-to-file`
42
+ * @property {string} key
43
+ * If this property is set, it will be converted to md5, to
44
+ * check if a file with this name exists.
45
+ * If it exists, the absolute path is returned (no network
46
+ * activity takes place )
47
+ * If it doesn't exist, the file is downloaded as usual
48
+ * @property {number} timeout
49
+ * Request timeout in millionseconds, by default it's 60000ms.
50
+ * @property {boolean} followRedirect
51
+ * Follow redirects automatically, default true
52
+ * @property {boolean} trusty
53
+ * Trust all certificates
54
+ * @property {boolean} wifiOnly
55
+ * Only do requests through WiFi. Android SDK 21 or above only.
56
+ *
57
+ * @return {function} This method returns a `fetch` method instance.
58
+ */
59
+ export function config(options: ReactNativeBlobUtilConfig) {
60
+ return {fetch: fetch.bind(options)};
61
+ }
62
+
63
+ /**
64
+ * Fetch from file system, use the same interface as RNFB.fetch
65
+ * @param {ReactNativeBlobUtilConfig} [options={}] Fetch configurations
66
+ * @param {string} method Should be one of `get`, `post`, `put`
67
+ * @param {string} url A file URI string
68
+ * @param {string} headers Arguments of file system API
69
+ * @param {any} body Data to put or post to file systen.
70
+ * @return {Promise}
71
+ */
72
+ function fetchFile(options = {}, method, url, headers = {}, body): Promise {
73
+
74
+ if (!URIUtil.isFileURI(url)) {
75
+ throw `could not fetch file from an invalid URI : ${url}`;
76
+ }
77
+
78
+ url = URIUtil.unwrapFileURI(url);
79
+
80
+ let promise = null,
81
+ cursor = 0,
82
+ total = -1,
83
+ cacheData = '',
84
+ info = null,
85
+ _progress, _uploadProgress, _stateChange;
86
+
87
+ switch (method.toLowerCase()) {
88
+
89
+ case 'post':
90
+ break;
91
+
92
+ case 'put':
93
+ break;
94
+
95
+ // read data from file system
96
+ default:
97
+ promise = fs.stat(url)
98
+ .then((stat) => {
99
+ total = stat.size;
100
+ return fs.readStream(url,
101
+ headers.encoding || 'utf8',
102
+ Math.floor(headers.bufferSize) || 409600,
103
+ Math.floor(headers.interval) || 100
104
+ );
105
+ })
106
+ .then((stream) => new Promise((resolve, reject) => {
107
+ stream.open();
108
+ info = {
109
+ state: '2',
110
+ headers: {'source': 'system-fs'},
111
+ status: 200,
112
+ respType: 'text',
113
+ rnfbEncode: headers.encoding || 'utf8'
114
+ };
115
+ _stateChange(info);
116
+ stream.onData((chunk) => {
117
+ _progress && _progress(cursor, total, chunk);
118
+ if (headers.noCache)
119
+ return;
120
+ cacheData += chunk;
121
+ });
122
+ stream.onError((err) => {
123
+ reject(err);
124
+ });
125
+ stream.onEnd(() => {
126
+ resolve(new FetchBlobResponse(null, info, cacheData));
127
+ });
128
+ }));
129
+ break;
130
+ }
131
+
132
+ promise.progress = (fn) => {
133
+ _progress = fn;
134
+ return promise;
135
+ };
136
+ promise.stateChange = (fn) => {
137
+ _stateChange = fn;
138
+ return promise;
139
+ };
140
+ promise.uploadProgress = (fn) => {
141
+ _uploadProgress = fn;
142
+ return promise;
143
+ };
144
+
145
+ return promise;
146
+ }
147
+
148
+ /**
149
+ * Create a HTTP request by settings, the `this` context is a `ReactNativeBlobUtilConfig` object.
150
+ * @param {string} method HTTP method, should be `GET`, `POST`, `PUT`, `DELETE`
151
+ * @param {string} url Request target url string.
152
+ * @param {object} headers HTTP request headers.
153
+ * @param {string} body
154
+ * Request body, can be either a BASE64 encoded data string,
155
+ * or a file path with prefix `ReactNativeBlobUtil-file://` (can be changed)
156
+ * @return {Promise}
157
+ * This promise instance also contains a Customized method `progress`for
158
+ * register progress event handler.
159
+ */
160
+ export function fetch(...args: any): Promise {
161
+
162
+ // create task ID for receiving progress event
163
+ let taskId = getUUID();
164
+ let options = this || {};
165
+ let subscription, subscriptionUpload, stateEvent, partEvent;
166
+ let respInfo = {'uninit': true};
167
+ let [method, url, headers, body] = [...args];
168
+
169
+ // # 241 normalize null or undefined headers, in case nil or null string
170
+ // pass to native context
171
+ headers = headers && Object.keys(headers).reduce((result, key) => {
172
+ result[key] = headers[key] || '';
173
+ return result;
174
+ }, {});
175
+
176
+ // fetch from file system
177
+ if (URIUtil.isFileURI(url)) {
178
+ return fetchFile(options, method, url, headers, body);
179
+ }
180
+
181
+ let promiseResolve;
182
+ let promiseReject;
183
+
184
+ // from remote HTTP(S)
185
+ let promise = new Promise((resolve, reject) => {
186
+ promiseResolve = resolve;
187
+ promiseReject = reject;
188
+
189
+ let nativeMethodName = Array.isArray(body) ? 'fetchBlobForm' : 'fetchBlob';
190
+
191
+ // on progress event listener
192
+ subscription = eventEmitter.addListener('ReactNativeBlobUtilProgress', (e) => {
193
+ if (typeof e === 'string') e = JSON.parse(e);
194
+ if (e.taskId === taskId && promise.onProgress) {
195
+ promise.onProgress(e.written, e.total, e.chunk);
196
+ }
197
+ });
198
+
199
+ subscriptionUpload = eventEmitter.addListener('ReactNativeBlobUtilProgress-upload', (e) => {
200
+ if (typeof e === 'string') e = JSON.parse(e);
201
+ if (e.taskId === taskId && promise.onUploadProgress) {
202
+ promise.onUploadProgress(e.written, e.total);
203
+ }
204
+ });
205
+
206
+ stateEvent = eventEmitter.addListener('ReactNativeBlobUtilState', (e) => {
207
+ if (typeof e === 'string') e = JSON.parse(e);
208
+ if (e.taskId === taskId)
209
+ respInfo = e;
210
+ promise.onStateChange && promise.onStateChange(e);
211
+ });
212
+
213
+ subscription = eventEmitter.addListener('ReactNativeBlobUtilExpire', (e) => {
214
+ if (typeof e === 'string') e = JSON.parse(e);
215
+ if (e.taskId === taskId && promise.onExpire) {
216
+ promise.onExpire(e);
217
+ }
218
+ });
219
+
220
+ partEvent = eventEmitter.addListener('ReactNativeBlobUtilServerPush', (e) => {
221
+ if (typeof e === 'string') e = JSON.parse(e);
222
+ if (e.taskId === taskId && promise.onPartData) {
223
+ promise.onPartData(e.chunk);
224
+ }
225
+ });
226
+
227
+ // When the request body comes from Blob polyfill, we should use special its ref
228
+ // as the request body
229
+ if (body instanceof Blob && body.isReactNativeBlobUtilPolyfill) {
230
+ body = body.getReactNativeBlobUtilRef();
231
+ }
232
+
233
+ let req = ReactNativeBlobUtil[nativeMethodName];
234
+
235
+ /**
236
+ * Send request via native module, the response callback accepts three arguments
237
+ * @callback
238
+ * @param err {any} Error message or object, when the request success, this
239
+ * parameter should be `null`.
240
+ * @param rawType { 'utf8' | 'base64' | 'path'} RNFB request will be stored
241
+ * as UTF8 string, BASE64 string, or a file path reference
242
+ * in JS context, and this parameter indicates which one
243
+ * dose the response data presents.
244
+ * @param data {string} Response data or its reference.
245
+ * @param responseInfo {Object.<>}
246
+ */
247
+ req(options, taskId, method, url, headers || {}, body, (err, rawType, data, responseInfo) => {
248
+
249
+ // task done, remove event listeners
250
+ subscription.remove();
251
+ subscriptionUpload.remove();
252
+ stateEvent.remove();
253
+ partEvent.remove();
254
+ delete promise.progress;
255
+ delete promise.uploadProgress;
256
+ delete promise.stateChange;
257
+ delete promise.part;
258
+ delete promise.cancel;
259
+ // delete promise['expire']
260
+ promise.cancel = () => {
261
+ };
262
+
263
+ if(!responseInfo) responseInfo = {}; // should not be null / undefined
264
+
265
+ if (err)
266
+ reject(new Error(err, respInfo));
267
+ else {
268
+ // response data is saved to storage, create a session for it
269
+ if (options.path || options.fileCache || options.addAndroidDownloads
270
+ || options.key || options.auto && respInfo.respType === 'blob') {
271
+ if (options.session)
272
+ fs.session(options.session).add(data);
273
+ }
274
+ if ('uninit' in respInfo && respInfo.uninit) // event didn't fire yet so we override it here
275
+ respInfo = responseInfo;
276
+
277
+ respInfo.rnfbEncode = rawType;
278
+ resolve(new FetchBlobResponse(taskId, respInfo, data));
279
+ }
280
+
281
+ });
282
+
283
+ });
284
+
285
+ // extend Promise object, add `progress`, `uploadProgress`, and `cancel`
286
+ // method for register progress event handler and cancel request.
287
+ // Add second parameter for performance purpose #140
288
+ // When there's only one argument pass to this method, use default `interval`
289
+ // and `count`, otherwise use the given on.
290
+ // TODO : code refactor, move `uploadProgress` and `progress` to StatefulPromise
291
+ promise.progress = (...args) => {
292
+ let interval = 250;
293
+ let count = -1;
294
+ let fn = () => {
295
+ };
296
+ if (args.length === 2) {
297
+ interval = args[0].interval || interval;
298
+ count = args[0].count || count;
299
+ fn = args[1];
300
+ }
301
+ else {
302
+ fn = args[0];
303
+ }
304
+ promise.onProgress = fn;
305
+ ReactNativeBlobUtil.enableProgressReport(taskId, interval, count);
306
+ return promise;
307
+ };
308
+ promise.uploadProgress = (...args) => {
309
+ let interval = 250;
310
+ let count = -1;
311
+ let fn = () => {
312
+ };
313
+ if (args.length === 2) {
314
+ interval = args[0].interval || interval;
315
+ count = args[0].count || count;
316
+ fn = args[1];
317
+ }
318
+ else {
319
+ fn = args[0];
320
+ }
321
+ promise.onUploadProgress = fn;
322
+ ReactNativeBlobUtil.enableUploadProgressReport(taskId, interval, count);
323
+ return promise;
324
+ };
325
+ promise.part = (fn) => {
326
+ promise.onPartData = fn;
327
+ return promise;
328
+ };
329
+ promise.stateChange = (fn) => {
330
+ promise.onStateChange = fn;
331
+ return promise;
332
+ };
333
+ promise.expire = (fn) => {
334
+ promise.onExpire = fn;
335
+ return promise;
336
+ };
337
+ promise.cancel = (fn) => {
338
+ fn = fn || function () {
339
+ };
340
+ subscription.remove();
341
+ subscriptionUpload.remove();
342
+ stateEvent.remove();
343
+ ReactNativeBlobUtil.cancelRequest(taskId, fn);
344
+ promiseReject(new CanceledFetchError('canceled'));
345
+ };
346
+ promise.taskId = taskId;
347
+
348
+ return promise;
349
+
350
+ }