@react-native-firebase/storage 20.0.0 → 20.2.0

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,16 @@
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
+ ## [20.2.0](https://github.com/invertase/react-native-firebase/compare/v20.1.0...v20.2.0) (2024-07-15)
7
+
8
+ ### Features
9
+
10
+ - **other:** Add Storage support ([#7888](https://github.com/invertase/react-native-firebase/issues/7888)) ([9b8dda7](https://github.com/invertase/react-native-firebase/commit/9b8dda704a01243039624bfcc7614021e6c3a527))
11
+
12
+ ## [20.1.0](https://github.com/invertase/react-native-firebase/compare/v20.0.0...v20.1.0) (2024-06-04)
13
+
14
+ **Note:** Version bump only for package @react-native-firebase/storage
15
+
6
16
  ## [20.0.0](https://github.com/invertase/react-native-firebase/compare/v19.3.0...v20.0.0) (2024-05-20)
7
17
 
8
18
  **Note:** Version bump only for package @react-native-firebase/storage
package/lib/index.js CHANGED
@@ -16,6 +16,7 @@
16
16
  */
17
17
 
18
18
  import { isAndroid, isNumber, isString } from '@react-native-firebase/app/lib/common';
19
+ import { setReactNativeModule } from '@react-native-firebase/app/lib/internal/nativeModule';
19
20
  import {
20
21
  createModuleNamespace,
21
22
  FirebaseModule,
@@ -25,6 +26,7 @@ import StorageReference from './StorageReference';
25
26
  import StorageStatics from './StorageStatics';
26
27
  import { getGsUrlParts, getHttpUrlParts, handleStorageEvent } from './utils';
27
28
  import version from './version';
29
+ import fallBackModule from './web/RNFBStorageModule';
28
30
 
29
31
  export {
30
32
  getStorage,
@@ -230,3 +232,5 @@ export default createModuleNamespace({
230
232
  // storage().X(...);
231
233
  // firebase.storage().X(...);
232
234
  export const firebase = getFirebaseRoot();
235
+
236
+ setReactNativeModule(nativeModuleName, fallBackModule);
package/lib/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- module.exports = '20.0.0';
2
+ module.exports = '20.2.0';
@@ -0,0 +1,2 @@
1
+ // No-op for android.
2
+ export default {};
@@ -0,0 +1,2 @@
1
+ // No-op for ios.
2
+ export default {};
@@ -0,0 +1,462 @@
1
+ import {
2
+ getApps,
3
+ connectStorageEmulator,
4
+ getApp,
5
+ getStorage,
6
+ deleteObject,
7
+ getDownloadURL,
8
+ getMetadata,
9
+ list,
10
+ listAll,
11
+ updateMetadata,
12
+ uploadBytesResumable,
13
+ ref as firebaseStorageRef,
14
+ } from '@react-native-firebase/app/lib/internal/web/firebaseStorage';
15
+ import { guard, getWebError, emitEvent } from '@react-native-firebase/app/lib/internal/web/utils';
16
+ import { Base64 } from '@react-native-firebase/app/lib/common';
17
+
18
+ function rejectWithCodeAndMessage(code, message) {
19
+ return Promise.reject(
20
+ getWebError({
21
+ code,
22
+ message,
23
+ }),
24
+ );
25
+ }
26
+
27
+ function metadataToObject(metadata) {
28
+ const out = {
29
+ bucket: metadata.bucket,
30
+ generation: metadata.generation,
31
+ metageneration: metadata.metageneration,
32
+ fullPath: metadata.fullPath,
33
+ name: metadata.name,
34
+ size: metadata.size,
35
+ timeCreated: metadata.timeCreated,
36
+ updated: metadata.updated,
37
+ md5Hash: metadata.md5Hash,
38
+ };
39
+
40
+ if ('cacheControl' in metadata) {
41
+ out.cacheControl = metadata.cacheControl;
42
+ }
43
+
44
+ if ('contentLanguage' in metadata) {
45
+ out.contentLanguage = metadata.contentLanguage;
46
+ }
47
+
48
+ if ('contentDisposition' in metadata) {
49
+ out.contentDisposition = metadata.contentDisposition;
50
+ }
51
+
52
+ if ('contentEncoding' in metadata) {
53
+ out.contentEncoding = metadata.contentEncoding;
54
+ }
55
+
56
+ if ('contentType' in metadata) {
57
+ out.contentType = metadata.contentType;
58
+ }
59
+
60
+ if ('customMetadata' in metadata) {
61
+ out.customMetadata = metadata.customMetadata;
62
+ // To match Android/iOS
63
+ out.metadata = metadata.customMetadata;
64
+ }
65
+
66
+ return out;
67
+ }
68
+
69
+ function uploadTaskErrorToObject(error, snapshot) {
70
+ return {
71
+ ...uploadTaskSnapshotToObject(snapshot),
72
+ state: 'error',
73
+ error: getWebError(error),
74
+ };
75
+ }
76
+
77
+ function uploadTaskSnapshotToObject(snapshot) {
78
+ return {
79
+ totalBytes: snapshot ? snapshot.totalBytes : 0,
80
+ bytesTransferred: snapshot ? snapshot.bytesTransferred : 0,
81
+ state: snapshot ? taskStateToString(snapshot.state) : 'unknown',
82
+ metadata: snapshot ? metadataToObject(snapshot.metadata) : {},
83
+ };
84
+ }
85
+
86
+ function taskStateToString(state) {
87
+ const override = {
88
+ canceled: 'cancelled',
89
+ };
90
+
91
+ if (state in override) {
92
+ return override[state];
93
+ }
94
+
95
+ return state;
96
+ }
97
+
98
+ function makeSettableMetadata(metadata) {
99
+ return {
100
+ cacheControl: metadata.cacheControl,
101
+ contentDisposition: metadata.contentDisposition,
102
+ contentEncoding: metadata.contentEncoding,
103
+ contentType: metadata.contentType,
104
+ contentLanguage: metadata.contentLanguage,
105
+ customMetadata: metadata.customMetadata,
106
+ };
107
+ }
108
+
109
+ function listResultToObject(result) {
110
+ return {
111
+ nextPageToken: result.nextPageToken,
112
+ items: result.items.map(ref => ref.fullPath),
113
+ prefixes: result.prefixes.map(ref => ref.fullPath),
114
+ };
115
+ }
116
+
117
+ const emulatorForApp = {};
118
+ const appInstances = {};
119
+ const storageInstances = {};
120
+ const tasks = {};
121
+
122
+ function getBucketFromUrl(url) {
123
+ const pathWithBucketName = url.substring(5);
124
+ const bucket = url.substring(0, pathWithBucketName.indexOf('/') + 5);
125
+ return bucket;
126
+ }
127
+
128
+ function getCachedAppInstance(appName) {
129
+ return (appInstances[appName] ??= getApp(appName));
130
+ }
131
+
132
+ // Returns a cached Storage instance.
133
+ function getCachedStorageInstance(appName, url) {
134
+ let instance;
135
+ if (!url) {
136
+ instance = getCachedStorageInstance(
137
+ appName,
138
+ getCachedAppInstance(appName).options.storageBucket,
139
+ );
140
+ } else {
141
+ const bucket = getBucketFromUrl(url);
142
+ instance = storageInstances[`${appName}|${bucket}`] ??= getStorage(
143
+ getCachedAppInstance(appName),
144
+ bucket,
145
+ );
146
+ }
147
+ if (emulatorForApp[appName]) {
148
+ connectStorageEmulator(instance, emulatorForApp[appName].host, emulatorForApp[appName].port);
149
+ }
150
+ return instance;
151
+ }
152
+
153
+ // Returns a Storage Reference.
154
+ function getReferenceFromUrl(appName, url) {
155
+ const path = url.substring(url.indexOf('/') + 1);
156
+ const instance = getCachedStorageInstance(appName, path);
157
+ return firebaseStorageRef(instance, url);
158
+ }
159
+
160
+ const CONSTANTS = {};
161
+ const defaultAppInstance = getApps()[0];
162
+
163
+ if (defaultAppInstance) {
164
+ CONSTANTS.maxDownloadRetryTime = 0;
165
+ CONSTANTS.maxOperationRetryTime = 0;
166
+ CONSTANTS.maxUploadRetryTime = 0;
167
+ }
168
+
169
+ export default {
170
+ ...CONSTANTS,
171
+
172
+ /**
173
+ * Delete an object at the path.
174
+ * @param {string} appName - The app name.
175
+ * @param {string} url - The path to the object.
176
+ * @return {Promise<void>}
177
+ */
178
+ delete(appName, url) {
179
+ return guard(async () => {
180
+ const ref = getReferenceFromUrl(appName, url);
181
+ await deleteObject(ref);
182
+ });
183
+ },
184
+
185
+ /**
186
+ * Get the download URL for an object.
187
+ * @param {string} appName - The app name.
188
+ * @param {string} url - The path to the object.
189
+ * @return {Promise<string>} The download URL.
190
+ */
191
+ getDownloadURL(appName, url) {
192
+ return guard(async () => {
193
+ const ref = getReferenceFromUrl(appName, url);
194
+ const downloadURL = await getDownloadURL(ref);
195
+ return downloadURL;
196
+ });
197
+ },
198
+
199
+ /**
200
+ * Get the metadata for an object.
201
+ * @param {string} appName - The app name.
202
+ * @param {string} url - The path to the object.
203
+ * @return {Promise<Object>} The metadata.
204
+ */
205
+ getMetadata(appName, url) {
206
+ return guard(async () => {
207
+ const ref = getReferenceFromUrl(appName, url);
208
+ const metadata = await getMetadata(ref);
209
+ return metadataToObject(metadata);
210
+ });
211
+ },
212
+
213
+ /**
214
+ * List objects at the path.
215
+ * @param {string} appName - The app name.
216
+ * @param {string} url - The path to the object.
217
+ * @param {Object} listOptions - The list options.
218
+ * @return {Promise<Object>} The list result.
219
+ */
220
+ list(appName, url, listOptions) {
221
+ return guard(async () => {
222
+ const ref = getReferenceFromUrl(appName, url);
223
+ const listResult = await list(ref, listOptions);
224
+ return listResultToObject(listResult);
225
+ });
226
+ },
227
+
228
+ /**
229
+ * List all objects at the path.
230
+ * @param {string} appName - The app name.
231
+ * @param {string} url - The path to the object.
232
+ * @return {Promise<Object>} The list result.
233
+ */
234
+ listAll(appName, url) {
235
+ return guard(async () => {
236
+ const ref = getReferenceFromUrl(appName, url);
237
+ const listResult = await listAll(ref);
238
+ return listResultToObject(listResult);
239
+ });
240
+ },
241
+
242
+ /**
243
+ * Update the metadata for an object.
244
+ * @param {string} appName - The app name.
245
+ * @param {string} url - The path to the object.
246
+ * @param {Object} metadata - The metadata (SettableMetadata).
247
+ */
248
+ updateMetadata(appName, url, metadata) {
249
+ return guard(async () => {
250
+ const ref = getReferenceFromUrl(appName, url);
251
+ const updated = await updateMetadata(ref, makeSettableMetadata(metadata));
252
+ return metadataToObject(updated);
253
+ });
254
+ },
255
+
256
+ setMaxDownloadRetryTime() {
257
+ if (__DEV__) {
258
+ // eslint-disable-next-line no-console
259
+ console.warn(
260
+ 'The Firebase Storage `setMaxDownloadRetryTime` method is not available in the this environment.',
261
+ );
262
+ return;
263
+ }
264
+ },
265
+
266
+ /**
267
+ * Set the maximum operation retry time.
268
+ * @param {string} appName - The app name.
269
+ * @param {number} milliseconds - The maximum operation retry time.
270
+ * @return {Promise<void>}
271
+ */
272
+ setMaxOperationRetryTime(appName, milliseconds) {
273
+ return guard(async () => {
274
+ const storage = getCachedStorageInstance(appName);
275
+ storage.maxOperationRetryTime = milliseconds;
276
+ });
277
+ },
278
+
279
+ /**
280
+ * Set the maximum upload retry time.
281
+ * @param {string} appName - The app name.
282
+ * @param {number} milliseconds - The maximum upload retry time.
283
+ * @return {Promise<void>}
284
+ */
285
+ setMaxUploadRetryTime(appName, milliseconds) {
286
+ return guard(async () => {
287
+ const storage = getCachedStorageInstance(appName);
288
+ storage.maxUploadRetryTime = milliseconds;
289
+ });
290
+ },
291
+
292
+ /**
293
+ * Use the Firebase Storage emulator.
294
+ * @param {string} appName - The app name.
295
+ * @param {string} host - The emulator host.
296
+ * @param {number} port - The emulator port.
297
+ * @return {Promise<void>}
298
+ */
299
+ useEmulator(appName, host, port) {
300
+ return guard(async () => {
301
+ const instance = getCachedStorageInstance(appName);
302
+ connectStorageEmulator(instance, host, port);
303
+ emulatorForApp[appName] = { host, port };
304
+ });
305
+ },
306
+
307
+ writeToFile() {
308
+ return rejectWithCodeAndMessage(
309
+ 'unsupported',
310
+ 'This operation is not supported in this environment.',
311
+ );
312
+ },
313
+
314
+ /**
315
+ * Put a string to the path.
316
+ * @param {string} appName - The app name.
317
+ * @param {string} url - The path to the object.
318
+ * @param {string} string - The string to put.
319
+ * @param {string} format - The format of the string.
320
+ * @param {Object} metadata - The metadata (SettableMetadata).
321
+ * @param {string} taskId - The task ID.
322
+ * @return {Promise<Object>} The upload snapshot.
323
+ */
324
+ putString(appName, url, string, format, metadata = {}, taskId) {
325
+ return guard(async () => {
326
+ const ref = getReferenceFromUrl(appName, url);
327
+
328
+ let base64String = null;
329
+
330
+ switch (format) {
331
+ case 'base64':
332
+ base64String = Base64.atob(string);
333
+ break;
334
+ case 'base64url':
335
+ base64String = Base64.atob(string.replace(/_/g, '/').replace(/-/g, '+'));
336
+ break;
337
+ }
338
+
339
+ const byteArray = new Uint8Array(base64String ? base64String.length : 0);
340
+
341
+ if (base64String) {
342
+ for (let i = 0; i < base64String.length; i++) {
343
+ byteArray[i] = base64String.charCodeAt(i);
344
+ }
345
+ }
346
+
347
+ // Start a resumable upload task.
348
+ const task = uploadBytesResumable(ref, byteArray, {
349
+ ...makeSettableMetadata(metadata),
350
+ md5Hash: metadata.md5Hash,
351
+ });
352
+
353
+ // Store the task in the tasks map.
354
+ tasks[taskId] = task;
355
+
356
+ const snapshot = await new Promise((resolve, reject) => {
357
+ task.on(
358
+ 'state_changed',
359
+ snapshot => {
360
+ const event = {
361
+ body: uploadTaskSnapshotToObject(snapshot),
362
+ appName,
363
+ taskId,
364
+ eventName: 'state_changed',
365
+ };
366
+ emitEvent('storage_event', event);
367
+ },
368
+ error => {
369
+ const errorSnapshot = uploadTaskErrorToObject(error, task.snapshot);
370
+ const event = {
371
+ body: {
372
+ ...errorSnapshot,
373
+ state: 'error',
374
+ },
375
+ appName,
376
+ taskId,
377
+ eventName: 'state_changed',
378
+ };
379
+ emitEvent('storage_event', event);
380
+ emitEvent('storage_event', {
381
+ ...event,
382
+ eventName: 'upload_failure',
383
+ });
384
+ delete tasks[taskId];
385
+ reject(error);
386
+ },
387
+ () => {
388
+ delete tasks[taskId];
389
+ const event = {
390
+ body: {
391
+ ...uploadTaskSnapshotToObject(snapshot),
392
+ state: 'success',
393
+ },
394
+ appName,
395
+ taskId,
396
+ eventName: 'state_changed',
397
+ };
398
+ emitEvent('storage_event', event);
399
+ emitEvent('storage_event', {
400
+ ...event,
401
+ eventName: 'upload_success',
402
+ });
403
+ resolve(task.snapshot);
404
+ },
405
+ );
406
+ });
407
+
408
+ return uploadTaskSnapshotToObject(snapshot);
409
+ });
410
+ },
411
+
412
+ putFile() {
413
+ return rejectWithCodeAndMessage(
414
+ 'unsupported',
415
+ 'This operation is not supported in this environment.',
416
+ );
417
+ },
418
+
419
+ /**
420
+ * Set the status of a task.
421
+ * @param {string} appName - The app name.
422
+ * @param {string} taskId - The task ID.
423
+ * @param {number} status - The status.
424
+ * @return {Promise<boolean>} Whether the status was set.
425
+ */
426
+ setTaskStatus(appName, taskId, status) {
427
+ // TODO this function implementation cannot
428
+ // be tested right now since we're unable
429
+ // to create a big enough upload to be able to
430
+ // pause/resume/cancel it in time.
431
+ return guard(async () => {
432
+ const task = tasks[taskId];
433
+
434
+ // If the task doesn't exist, return false.
435
+ if (!task) {
436
+ return false;
437
+ }
438
+
439
+ let result = false;
440
+
441
+ switch (status) {
442
+ case 0:
443
+ result = await task.pause();
444
+ break;
445
+ case 1:
446
+ result = await task.resume();
447
+ break;
448
+ case 2:
449
+ result = await task.cancel();
450
+ break;
451
+ }
452
+
453
+ emitEvent('storage_event', {
454
+ data: buildUploadSnapshotMap(task.snapshot),
455
+ appName,
456
+ taskId,
457
+ });
458
+
459
+ return result;
460
+ });
461
+ },
462
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native-firebase/storage",
3
- "version": "20.0.0",
3
+ "version": "20.2.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": "20.0.0"
32
+ "@react-native-firebase/app": "20.2.0"
33
33
  },
34
34
  "publishConfig": {
35
35
  "access": "public"
36
36
  },
37
- "gitHead": "b6079dd09ed1f6e47dc782df0d98c5479bfc0cd4"
37
+ "gitHead": "82c50138d07e673213cd8dee5ce9a2f9b5656649"
38
38
  }