@react-native-firebase/storage 20.0.0 → 20.2.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 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
  }