@react-native-firebase/storage 14.11.1 → 15.0.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/CHANGELOG.md +16 -0
- package/android/src/main/java/io/invertase/firebase/storage/ReactNativeFirebaseStorageCommon.java +42 -15
- package/android/src/main/java/io/invertase/firebase/storage/ReactNativeFirebaseStorageModule.java +42 -6
- package/android/src/main/java/io/invertase/firebase/storage/ReactNativeFirebaseStorageUploadTask.java +2 -2
- package/ios/RNFBStorage/RNFBStorageCommon.h +2 -1
- package/ios/RNFBStorage/RNFBStorageCommon.m +65 -4
- package/ios/RNFBStorage/RNFBStorageModule.m +23 -12
- package/lib/index.d.ts +1 -1
- package/lib/utils.js +2 -2
- package/lib/version.js +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
@@ -3,6 +3,22 @@
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
5
5
|
|
6
|
+
# [15.0.0](https://github.com/invertase/react-native-firebase/compare/v14.11.1...v15.0.0) (2022-06-20)
|
7
|
+
|
8
|
+
### Bug Fixes
|
9
|
+
|
10
|
+
- **storage, ios:** correct storage metadata update / delete ([2dcb079](https://github.com/invertase/react-native-firebase/commit/2dcb0790c1812a33100cceea9dcb407d6a64cb87))
|
11
|
+
- **storage, ios:** surface underlying reason for unknown errors if possible ([6cd53ea](https://github.com/invertase/react-native-firebase/commit/6cd53eaca16ef52c52a28a7b209a7c8313fef08b))
|
12
|
+
|
13
|
+
- fix(storage, android)!: android now updates customMetadata as a group ([d602436](https://github.com/invertase/react-native-firebase/commit/d602436795bfb78f24bc69c42880133505738c00))
|
14
|
+
|
15
|
+
### BREAKING CHANGES
|
16
|
+
|
17
|
+
- android works like web+iOS now: customMetadata if passed in will be
|
18
|
+
updated as a single atomic unit, all keys at once. Any key you want to keep in customMetadata
|
19
|
+
must be passed in during update; any missing keys will be removed. Set customMetadata to null
|
20
|
+
in order to remove customMetadata entirely, omit it during update to leave it unchanged.
|
21
|
+
|
6
22
|
## [14.11.1](https://github.com/invertase/react-native-firebase/compare/v14.11.0...v14.11.1) (2022-06-17)
|
7
23
|
|
8
24
|
**Note:** Version bump only for package @react-native-firebase/storage
|
package/android/src/main/java/io/invertase/firebase/storage/ReactNativeFirebaseStorageCommon.java
CHANGED
@@ -36,9 +36,9 @@ import com.google.firebase.storage.StorageReference;
|
|
36
36
|
import com.google.firebase.storage.StorageTask;
|
37
37
|
import io.invertase.firebase.app.ReactNativeFirebaseApp;
|
38
38
|
import io.invertase.firebase.common.SharedUtils;
|
39
|
+
import java.util.HashMap;
|
39
40
|
import java.util.Locale;
|
40
41
|
import java.util.Map;
|
41
|
-
import java.util.Objects;
|
42
42
|
import javax.annotation.Nullable;
|
43
43
|
|
44
44
|
class ReactNativeFirebaseStorageCommon {
|
@@ -93,15 +93,40 @@ class ReactNativeFirebaseStorageCommon {
|
|
93
93
|
}
|
94
94
|
|
95
95
|
/** Converts a RN ReadableMap into a StorageMetadata instance */
|
96
|
-
static StorageMetadata buildMetadataFromMap(
|
96
|
+
static StorageMetadata buildMetadataFromMap(
|
97
|
+
ReadableMap metadataMap, @Nullable Uri file, @Nullable StorageMetadata existingMetadata) {
|
97
98
|
StorageMetadata.Builder metadataBuilder = new StorageMetadata.Builder();
|
98
99
|
|
99
100
|
if (metadataMap != null) {
|
100
|
-
if (metadataMap.hasKey(KEY_CUSTOM_META)) {
|
101
|
-
|
102
|
-
Map<String, Object>
|
103
|
-
|
101
|
+
if (metadataMap.hasKey(KEY_CUSTOM_META) || (existingMetadata != null)) {
|
102
|
+
|
103
|
+
Map<String, Object> customMetadata = new HashMap<>();
|
104
|
+
ReadableMap freshCustomMetadata = metadataMap.getMap(KEY_CUSTOM_META);
|
105
|
+
Map<String, Object> existingCustomMetadata = new HashMap<>();
|
106
|
+
|
107
|
+
// Our baseline will be any existing custom metadata if it exists
|
108
|
+
if (existingMetadata != null) {
|
109
|
+
for (String existingKey : existingMetadata.getCustomMetadataKeys()) {
|
110
|
+
customMetadata.put(existingKey, existingMetadata.getCustomMetadata(existingKey));
|
111
|
+
existingCustomMetadata.put(
|
112
|
+
existingKey, existingMetadata.getCustomMetadata(existingKey));
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
// Clobber with any fresh custom metadata if it exists
|
117
|
+
if (freshCustomMetadata != null) {
|
118
|
+
customMetadata.putAll(freshCustomMetadata.toHashMap());
|
119
|
+
}
|
120
|
+
|
121
|
+
for (Map.Entry<String, Object> entry : customMetadata.entrySet()) {
|
104
122
|
metadataBuilder.setCustomMetadata(entry.getKey(), (String) entry.getValue());
|
123
|
+
|
124
|
+
// API contract updates custom metadata as a group but android SDK has key granularity
|
125
|
+
// So if freshCustomMetadata exists, for any key that in our merged map but not in
|
126
|
+
// freshCustomMetadata, set to null to clear
|
127
|
+
if (freshCustomMetadata == null || !freshCustomMetadata.hasKey(entry.getKey())) {
|
128
|
+
metadataBuilder.setCustomMetadata(entry.getKey(), null);
|
129
|
+
}
|
105
130
|
}
|
106
131
|
}
|
107
132
|
|
@@ -167,20 +192,24 @@ class ReactNativeFirebaseStorageCommon {
|
|
167
192
|
if (storageMetadata.getCacheControl() != null
|
168
193
|
&& storageMetadata.getCacheControl().length() > 0) {
|
169
194
|
metadata.putString(KEY_CACHE_CONTROL, storageMetadata.getCacheControl());
|
170
|
-
} else {
|
171
|
-
metadata.putNull(KEY_CACHE_CONTROL);
|
172
195
|
}
|
173
196
|
|
174
197
|
if (storageMetadata.getContentLanguage() != null
|
175
198
|
&& storageMetadata.getContentLanguage().length() > 0) {
|
176
199
|
metadata.putString(KEY_CONTENT_LANG, storageMetadata.getContentLanguage());
|
177
|
-
} else {
|
178
|
-
metadata.putNull(KEY_CONTENT_LANG);
|
179
200
|
}
|
180
201
|
|
181
|
-
|
182
|
-
|
183
|
-
|
202
|
+
if (storageMetadata.getContentDisposition() != null
|
203
|
+
&& storageMetadata.getContentDisposition().length() > 0) {
|
204
|
+
metadata.putString(KEY_CONTENT_DISPOSITION, storageMetadata.getContentDisposition());
|
205
|
+
}
|
206
|
+
if (storageMetadata.getContentEncoding() != null
|
207
|
+
&& storageMetadata.getContentEncoding().length() > 0) {
|
208
|
+
metadata.putString(KEY_CONTENT_ENCODING, storageMetadata.getContentEncoding());
|
209
|
+
}
|
210
|
+
if (storageMetadata.getContentType() != null && storageMetadata.getContentType().length() > 0) {
|
211
|
+
metadata.putString(KEY_CONTENT_TYPE, storageMetadata.getContentType());
|
212
|
+
}
|
184
213
|
|
185
214
|
if (storageMetadata.getCustomMetadataKeys().size() > 0) {
|
186
215
|
WritableMap customMetadata = Arguments.createMap();
|
@@ -188,8 +217,6 @@ class ReactNativeFirebaseStorageCommon {
|
|
188
217
|
customMetadata.putString(key, storageMetadata.getCustomMetadata(key));
|
189
218
|
}
|
190
219
|
metadata.putMap(KEY_CUSTOM_META, customMetadata);
|
191
|
-
} else {
|
192
|
-
metadata.putNull(KEY_CUSTOM_META);
|
193
220
|
}
|
194
221
|
|
195
222
|
return metadata;
|
package/android/src/main/java/io/invertase/firebase/storage/ReactNativeFirebaseStorageModule.java
CHANGED
@@ -169,6 +169,24 @@ public class ReactNativeFirebaseStorageModule extends ReactNativeFirebaseModule
|
|
169
169
|
}
|
170
170
|
}
|
171
171
|
|
172
|
+
// Useful for development / debugging
|
173
|
+
private void dumpMetadata(StorageMetadata metadata) {
|
174
|
+
System.err.println("STORAGE dumping metadata contents");
|
175
|
+
System.err.println("STORAGE - cacheControl " + metadata.getCacheControl());
|
176
|
+
System.err.println("STORAGE - contentDisposition " + metadata.getContentDisposition());
|
177
|
+
System.err.println("STORAGE - contentEncoding " + metadata.getContentEncoding());
|
178
|
+
System.err.println("STORAGE - contentLanguage " + metadata.getContentLanguage());
|
179
|
+
System.err.println("STORAGE - contentType " + metadata.getContentType());
|
180
|
+
for (String customKey : metadata.getCustomMetadataKeys()) {
|
181
|
+
System.err.println(
|
182
|
+
"STORAGE - customMetadata: '"
|
183
|
+
+ customKey
|
184
|
+
+ "' / '"
|
185
|
+
+ metadata.getCustomMetadata(customKey)
|
186
|
+
+ "'");
|
187
|
+
}
|
188
|
+
}
|
189
|
+
|
172
190
|
/**
|
173
191
|
* @link https://firebase.google.com/docs/reference/js/firebase.storage.Reference#updateMetadata
|
174
192
|
*/
|
@@ -177,17 +195,35 @@ public class ReactNativeFirebaseStorageModule extends ReactNativeFirebaseModule
|
|
177
195
|
String appName, String url, ReadableMap metadataMap, final Promise promise) {
|
178
196
|
try {
|
179
197
|
StorageReference reference = getReferenceFromUrl(url, appName);
|
180
|
-
StorageMetadata metadata = buildMetadataFromMap(metadataMap, null);
|
181
198
|
|
182
199
|
reference
|
183
|
-
.
|
200
|
+
.getMetadata()
|
184
201
|
.addOnCompleteListener(
|
185
202
|
getExecutor(),
|
186
|
-
|
187
|
-
if (
|
188
|
-
|
203
|
+
getTask -> {
|
204
|
+
if (getTask.isSuccessful()) {
|
205
|
+
|
206
|
+
// dumpMetadata(getTask.getResult());
|
207
|
+
StorageMetadata metadata =
|
208
|
+
buildMetadataFromMap(metadataMap, null, getTask.getResult());
|
209
|
+
// dumpMetadata(metadata);
|
210
|
+
|
211
|
+
reference
|
212
|
+
.updateMetadata(metadata)
|
213
|
+
.addOnCompleteListener(
|
214
|
+
getExecutor(),
|
215
|
+
updateTask -> {
|
216
|
+
if (updateTask.isSuccessful()) {
|
217
|
+
// dumpMetadata(updateTask.getResult());
|
218
|
+
promise.resolve(getMetadataAsMap(updateTask.getResult()));
|
219
|
+
} else {
|
220
|
+
updateTask.getException().printStackTrace();
|
221
|
+
promiseRejectStorageException(promise, updateTask.getException());
|
222
|
+
}
|
223
|
+
});
|
224
|
+
|
189
225
|
} else {
|
190
|
-
promiseRejectStorageException(promise,
|
226
|
+
promiseRejectStorageException(promise, getTask.getException());
|
191
227
|
}
|
192
228
|
});
|
193
229
|
} catch (Exception e) {
|
@@ -186,7 +186,7 @@ class ReactNativeFirebaseStorageUploadTask extends ReactNativeFirebaseStorageTas
|
|
186
186
|
|
187
187
|
/** Put String or Data from JavaScript */
|
188
188
|
void begin(ExecutorService executor, String string, String format, ReadableMap metadataMap) {
|
189
|
-
StorageMetadata metadata = buildMetadataFromMap(metadataMap, null);
|
189
|
+
StorageMetadata metadata = buildMetadataFromMap(metadataMap, null, null);
|
190
190
|
uploadTask = storageReference.putBytes(uploadStringToByteArray(string, format), metadata);
|
191
191
|
setStorageTask(uploadTask);
|
192
192
|
addEventListeners(executor);
|
@@ -195,7 +195,7 @@ class ReactNativeFirebaseStorageUploadTask extends ReactNativeFirebaseStorageTas
|
|
195
195
|
/** Put File from JavaScript */
|
196
196
|
void begin(ExecutorService executor, String localFilePath, ReadableMap metadataMap) {
|
197
197
|
Uri fileUri = SharedUtils.getUri(localFilePath);
|
198
|
-
StorageMetadata metadata = buildMetadataFromMap(metadataMap, fileUri);
|
198
|
+
StorageMetadata metadata = buildMetadataFromMap(metadataMap, fileUri, null);
|
199
199
|
uploadTask = storageReference.putFile(fileUri, metadata);
|
200
200
|
setStorageTask(uploadTask);
|
201
201
|
addEventListeners(executor);
|
@@ -56,7 +56,8 @@
|
|
56
56
|
|
57
57
|
+ (NSString *)getTaskStatus:(FIRStorageTaskStatus)status;
|
58
58
|
|
59
|
-
+ (FIRStorageMetadata *)buildMetadataFromMap:(NSDictionary *)metadata
|
59
|
+
+ (FIRStorageMetadata *)buildMetadataFromMap:(NSDictionary *)metadata
|
60
|
+
existingMetadata:(FIRStorageMetadata *)existingMetadata;
|
60
61
|
|
61
62
|
+ (NSArray *)getErrorCodeMessage:(NSError *)error;
|
62
63
|
|
@@ -392,9 +392,64 @@
|
|
392
392
|
}
|
393
393
|
}
|
394
394
|
|
395
|
-
+ (FIRStorageMetadata *)buildMetadataFromMap:(NSDictionary *)metadata
|
396
|
-
|
397
|
-
|
395
|
+
+ (FIRStorageMetadata *)buildMetadataFromMap:(NSDictionary *)metadata
|
396
|
+
existingMetadata:(nullable FIRStorageMetadata *)existingMetadata {
|
397
|
+
// If an existing metadata was passed in, modify it with our map, otherwise init a fresh copy
|
398
|
+
FIRStorageMetadata *storageMetadata = existingMetadata;
|
399
|
+
if (storageMetadata == nil) {
|
400
|
+
storageMetadata = [[FIRStorageMetadata alloc] init];
|
401
|
+
}
|
402
|
+
|
403
|
+
if (metadata[@"cacheControl"] == [NSNull null]) {
|
404
|
+
storageMetadata.cacheControl = nil;
|
405
|
+
} else {
|
406
|
+
storageMetadata.cacheControl = metadata[@"cacheControl"];
|
407
|
+
}
|
408
|
+
|
409
|
+
if (metadata[@"contentLanguage"] == [NSNull null]) {
|
410
|
+
storageMetadata.contentLanguage = nil;
|
411
|
+
} else {
|
412
|
+
storageMetadata.contentLanguage = metadata[@"contentLanguage"];
|
413
|
+
}
|
414
|
+
|
415
|
+
if (metadata[@"contentEncoding"] == [NSNull null]) {
|
416
|
+
storageMetadata.contentEncoding = nil;
|
417
|
+
} else {
|
418
|
+
storageMetadata.contentEncoding = metadata[@"contentEncoding"];
|
419
|
+
}
|
420
|
+
|
421
|
+
if (metadata[@"contentDisposition"] == [NSNull null]) {
|
422
|
+
storageMetadata.contentDisposition = nil;
|
423
|
+
} else {
|
424
|
+
storageMetadata.contentDisposition = metadata[@"contentDisposition"];
|
425
|
+
}
|
426
|
+
|
427
|
+
if (metadata[@"contentType"] == [NSNull null]) {
|
428
|
+
storageMetadata.contentType = nil;
|
429
|
+
} else {
|
430
|
+
storageMetadata.contentType = metadata[@"contentType"];
|
431
|
+
}
|
432
|
+
|
433
|
+
if (metadata[@"customMetadata"] == [NSNull null]) {
|
434
|
+
storageMetadata.customMetadata = @{};
|
435
|
+
} else {
|
436
|
+
NSMutableDictionary *customMetadata = [metadata[@"customMetadata"] mutableCopy];
|
437
|
+
for (NSString *key in customMetadata.allKeys) {
|
438
|
+
if (customMetadata[key] == [NSNull null] || customMetadata[key] == nil) {
|
439
|
+
[customMetadata removeObjectForKey:key];
|
440
|
+
}
|
441
|
+
}
|
442
|
+
storageMetadata.customMetadata = customMetadata;
|
443
|
+
}
|
444
|
+
|
445
|
+
// md5hash may be settable but is not update-able, so just test for existence and carry it in
|
446
|
+
// FIXME this will need a fix related to
|
447
|
+
// https://github.com/firebase/firebase-ios-sdk/issues/9849#issuecomment-1159292592 if
|
448
|
+
// (metadata[@"md5hash"]) {
|
449
|
+
// NSLog(@"STORAGE md5hash was set");
|
450
|
+
// storageMetadata.md5Hash = metadata[@"md5hash"];
|
451
|
+
// }
|
452
|
+
|
398
453
|
return storageMetadata;
|
399
454
|
}
|
400
455
|
|
@@ -417,7 +472,13 @@
|
|
417
472
|
code = @"invalid-device-file-path";
|
418
473
|
message = @"The specified device file path is invalid or is restricted.";
|
419
474
|
} else {
|
420
|
-
|
475
|
+
if (userInfo[@"ResponseBody"]) {
|
476
|
+
message =
|
477
|
+
[NSString stringWithFormat:@"An unknown error has occurred. (underlying reason '%@')",
|
478
|
+
userInfo[@"ResponseBody"]];
|
479
|
+
} else {
|
480
|
+
message = @"An unknown error has occurred.";
|
481
|
+
}
|
421
482
|
}
|
422
483
|
break;
|
423
484
|
case FIRStorageErrorCodeObjectNotFound:
|
@@ -143,17 +143,26 @@ RCT_EXPORT_METHOD(updateMetadata
|
|
143
143
|
: (RCTPromiseResolveBlock)resolve
|
144
144
|
: (RCTPromiseRejectBlock)reject) {
|
145
145
|
FIRStorageReference *storageReference = [self getReferenceFromUrl:url app:firebaseApp];
|
146
|
-
FIRStorageMetadata *storageMetadata = [RNFBStorageCommon buildMetadataFromMap:metadata];
|
147
146
|
|
148
|
-
[storageReference
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
147
|
+
[storageReference metadataWithCompletion:^(FIRStorageMetadata *_Nullable fetchedMetadata,
|
148
|
+
NSError *_Nullable error) {
|
149
|
+
if (error != nil) {
|
150
|
+
[self promiseRejectStorageException:reject error:error];
|
151
|
+
} else {
|
152
|
+
FIRStorageMetadata *storageMetadata =
|
153
|
+
[RNFBStorageCommon buildMetadataFromMap:metadata existingMetadata:fetchedMetadata];
|
154
|
+
|
155
|
+
[storageReference updateMetadata:storageMetadata
|
156
|
+
completion:^(FIRStorageMetadata *_Nullable updatedMetadata,
|
157
|
+
NSError *_Nullable error) {
|
158
|
+
if (error != nil) {
|
159
|
+
[self promiseRejectStorageException:reject error:error];
|
160
|
+
} else {
|
161
|
+
resolve([RNFBStorageCommon metadataToDict:updatedMetadata]);
|
162
|
+
}
|
163
|
+
}];
|
164
|
+
}
|
165
|
+
}];
|
157
166
|
}
|
158
167
|
|
159
168
|
/**
|
@@ -391,7 +400,8 @@ RCT_EXPORT_METHOD(putFile
|
|
391
400
|
: (nonnull NSNumber *)taskId
|
392
401
|
: (RCTPromiseResolveBlock)resolve
|
393
402
|
: (RCTPromiseRejectBlock)reject) {
|
394
|
-
FIRStorageMetadata *storageMetadata = [RNFBStorageCommon buildMetadataFromMap:metadata
|
403
|
+
FIRStorageMetadata *storageMetadata = [RNFBStorageCommon buildMetadataFromMap:metadata
|
404
|
+
existingMetadata:nil];
|
395
405
|
FIRStorageReference *storageReference = [self getReferenceFromUrl:url app:firebaseApp];
|
396
406
|
|
397
407
|
[RNFBStorageCommon
|
@@ -462,7 +472,8 @@ RCT_EXPORT_METHOD(putString
|
|
462
472
|
: (nonnull NSNumber *)taskId
|
463
473
|
: (RCTPromiseResolveBlock)resolve
|
464
474
|
: (RCTPromiseRejectBlock)reject) {
|
465
|
-
FIRStorageMetadata *storageMetadata = [RNFBStorageCommon buildMetadataFromMap:metadata
|
475
|
+
FIRStorageMetadata *storageMetadata = [RNFBStorageCommon buildMetadataFromMap:metadata
|
476
|
+
existingMetadata:nil];
|
466
477
|
FIRStorageReference *storageReference = [self getReferenceFromUrl:url app:firebaseApp];
|
467
478
|
|
468
479
|
__block FIRStorageUploadTask *uploadTask;
|
package/lib/index.d.ts
CHANGED
@@ -323,7 +323,7 @@ export namespace FirebaseStorageTypes {
|
|
323
323
|
/**
|
324
324
|
* Additional user-defined custom metadata for this storage object.
|
325
325
|
*
|
326
|
-
*
|
326
|
+
* All values must be strings. Set to null to delete all. Any keys ommitted during update will be removed.
|
327
327
|
*
|
328
328
|
* #### Example
|
329
329
|
*
|
package/lib/utils.js
CHANGED
@@ -88,9 +88,9 @@ export function validateMetadata(metadata, update = true) {
|
|
88
88
|
`firebase.storage.SettableMetadata invalid property '${key}' should be a string or null value.`,
|
89
89
|
);
|
90
90
|
}
|
91
|
-
} else if (!isObject(value)) {
|
91
|
+
} else if (!isObject(value) && !isNull(value)) {
|
92
92
|
throw new Error(
|
93
|
-
'firebase.storage.SettableMetadata.customMetadata must be an object of keys and string values.',
|
93
|
+
'firebase.storage.SettableMetadata.customMetadata must be an object of keys and string values or null value.',
|
94
94
|
);
|
95
95
|
}
|
96
96
|
}
|
package/lib/version.js
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
// Generated by genversion.
|
2
|
-
module.exports = '
|
2
|
+
module.exports = '15.0.0';
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@react-native-firebase/storage",
|
3
|
-
"version": "
|
3
|
+
"version": "15.0.0",
|
4
4
|
"author": "Invertase <oss@invertase.io> (http://invertase.io)",
|
5
5
|
"description": "React Native Firebase - React Native Firebase provides native integration with Cloud Storage, providing support to upload and download files directly from your device and from your Firebase Cloud Storage bucket.",
|
6
6
|
"main": "lib/index.js",
|
@@ -29,10 +29,10 @@
|
|
29
29
|
"download"
|
30
30
|
],
|
31
31
|
"peerDependencies": {
|
32
|
-
"@react-native-firebase/app": "
|
32
|
+
"@react-native-firebase/app": "15.0.0"
|
33
33
|
},
|
34
34
|
"publishConfig": {
|
35
35
|
"access": "public"
|
36
36
|
},
|
37
|
-
"gitHead": "
|
37
|
+
"gitHead": "7bb975c8c099083911a81e28050a2a5b50af2ee6"
|
38
38
|
}
|