From a6b7da2f48bc87c4646e0198113bf85cd79d2c21 Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Mon, 22 Jul 2024 11:57:04 +0100 Subject: [PATCH 1/4] chore: move modular to inside lib/ directory --- packages/storage/lib/index.js | 27 ++------------------- packages/storage/{ => lib}/modular/index.js | 0 2 files changed, 2 insertions(+), 25 deletions(-) rename packages/storage/{ => lib}/modular/index.js (100%) diff --git a/packages/storage/lib/index.js b/packages/storage/lib/index.js index 170d0ac316..850ce06e54 100644 --- a/packages/storage/lib/index.js +++ b/packages/storage/lib/index.js @@ -28,31 +28,6 @@ import { getGsUrlParts, getHttpUrlParts, handleStorageEvent } from './utils'; import version from './version'; import fallBackModule from './web/RNFBStorageModule'; -export { - getStorage, - connectStorageEmulator, - ref, - deleteObject, - getBlob, - getBytes, - getDownloadURL, - getMetadata, - getStream, - list, - listAll, - updateMetadata, - putFile, - writeToFile, - toString, - child, - setMaxDownloadRetryTime, - setMaxOperationRetryTime, - setMaxUploadRetryTime, - refFromURL, - uploadString, - uploadBytesResumable, -} from '../modular/index'; - const namespace = 'storage'; const nativeEvents = ['storage_event']; const nativeModuleName = 'RNFBStorageModule'; @@ -233,4 +208,6 @@ export default createModuleNamespace({ // firebase.storage().X(...); export const firebase = getFirebaseRoot(); +export * from './modular/index'; + setReactNativeModule(nativeModuleName, fallBackModule); diff --git a/packages/storage/modular/index.js b/packages/storage/lib/modular/index.js similarity index 100% rename from packages/storage/modular/index.js rename to packages/storage/lib/modular/index.js From 25242619caa98e8f05e76bf435cdb6c195413e07 Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Mon, 22 Jul 2024 13:42:53 +0100 Subject: [PATCH 2/4] chore: start update storage modular types --- packages/storage/lib/modular/index.d.ts | 165 ++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 packages/storage/lib/modular/index.d.ts diff --git a/packages/storage/lib/modular/index.d.ts b/packages/storage/lib/modular/index.d.ts new file mode 100644 index 0000000000..2346d9b741 --- /dev/null +++ b/packages/storage/lib/modular/index.d.ts @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { FirebaseApp } from '@firebase/app-types'; +import { FirebaseStorageTypes } from '../index'; + +import Storage = FirebaseStorageTypes.Module; +import Reference = FirebaseStorageTypes.Reference; +import FullMetadata = FirebaseStorageTypes.FullMetadata; +import ListResult = FirebaseStorageTypes.ListResult; +import TaskResult = FirebaseStorageTypes.TaskResult; +import Task = FirebaseStorageTypes.Task; +import ListOptions = FirebaseStorageTypes.ListOptions; +import SettableMetadata = FirebaseStorageTypes.SettableMetadata; +import EmulatorMockTokenOptions = FirebaseStorageTypes.EmulatorMockTokenOptions; + +/** + * Returns the existing default {@link Storage} instance that is associated with the + * default {@link FirebaseApp}. The default storage bucket is used. If no instance exists, initializes a new + * instance with default settings. + * + * @returns The {@link Storage} instance of the provided app. + */ +export declare function getStorage(): Storage; + +/** + * Returns the existing default {@link Storage} instance that is associated with the + * provided {@link FirebaseApp}. The default storage bucket is used. If no instance exists, initializes a new + * instance with default settings. + * + * @param app - The {@link FirebaseApp} instance that the returned {@link Storage} + * instance is associated with. + * @returns The {@link Firestore} instance of the provided app. + */ +export declare function getStorage(app?: FirebaseApp): Storage; + +/** + * Returns the existing default {@link Storage} instance that is associated with the + * provided {@link FirebaseApp}. If no instance exists, initializes a new + * instance with default settings. + * + * @param app - The {@link FirebaseApp} instance that the returned {@link Storage} + * instance is associated with. If `null` the default app is used. + * @param bucketUrl - The gs:// url to the Firebase Storage Bucket. If `null` the default bucket is used. + * @returns The {@link Firestore} instance of the provided app. + */ +export declare function getStorage(app?: FirebaseApp, bucketUrl?: string): Storage; + +export function getStorage(app?: FirebaseApp, bucketUrl?: string): Storage; +/** + * Modify this Storage instance to communicate with the Firebase Storage emulator. + * This must be called synchronously immediately following the first call to firebase.storage(). + * Do not use with production credentials as emulator traffic is not encrypted. + * + * Note: on android, hosts 'localhost' and '127.0.0.1' are automatically remapped to '10.0.2.2' (the + * "host" computer IP address for android emulators) to make the standard development experience easy. + * If you want to use the emulator on a real android device, you will need to specify the actual host + * computer IP address. + * + * @param storage: A reference to the `Storage` instance. + * @param host: emulator host (eg, 'localhost') + * @param port: emulator port (eg, 9199) + * @param options: Storage Emulator options. Web only. + */ +export function connectStorageEmulator( + storage: Storage, + host: string, + port: number, + options?: EmulatorMockTokenOptions, +): void; +/** + * Returns a new {@link Reference} instance. + * + * #### Example + * + * ```js + * const ref = firebase.storage().ref('cats.gif'); + * ``` + * + * @param path An optional string pointing to a location on the storage bucket. If no path + * is provided, the returned reference will be the bucket root path. + */ +export function ref(storage: Storage, path?: string): Reference; +/** + * Deletes the object at this reference's location. + * + * #### Example + * + * ```js + * const ref = firebase.storage().ref('invertase/logo.png'); + * await ref.delete(); + * ``` + */ +export function deleteObject(storageRef: Reference): Promise; + +export function getBlob(storageRef: Reference): Promise; + +export function getBytes(storageRef: Reference, maxDownloadSizeBytes: number): Promise; + +export function getDownloadURL(storageRef: Reference): Promise; + +export function getMetadata(storageRef: Reference): Promise; + +export function getStream( + storageRef: Reference, + maxDownloadSizeBytes: number, +): NodeJS.ReadableStream; + +export function list(storageRef: Reference, options?: ListOptions): Promise; + +export function listAll(storageRef: Reference): Promise; + +export function updateMetadata( + storageRef: Reference, + metadata: SettableMetadata, +): Promise; + +export function uploadBytes( + storageRef: Reference, + data: Blob | Uint8Array | ArrayBuffer, + metadata?: SettableMetadata, +): Promise; + +export function uploadBytesResumable( + storageRef: Reference, + data: Blob | Uint8Array | ArrayBuffer, + metadata?: SettableMetadata, +): Task; + +export function uploadString( + storageRef: Reference, + data: string, + format?: 'raw' | 'base64' | 'base64url' | 'data_url', + metadata?: SettableMetadata, +): Task; + +export function refFromURL(storage: Storage, url: string): Reference; + +export function setMaxOperationRetryTime(storage: Storage, time: number): Promise; + +export function setMaxUploadRetryTime(storage: Storage, time: number): Promise; + +export function putFile(storageRef: Reference, filePath: string, metadata?: SettableMetadata): Task; + +export function writeToFile(storageRef: Reference, filePath: string): Task; + +export function toString(storageRef: Reference): string; + +export function child(storageRef: Reference, path: string): Reference; + +export function setMaxDownloadRetryTime(storage: Storage, time: number): Promise; From b6c933a216ecef934e05428e9292d1af931a3332 Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Mon, 22 Jul 2024 13:54:43 +0100 Subject: [PATCH 3/4] chore(storage): update rest of types --- packages/storage/lib/modular/index.d.ts | 158 +++++++++++++++++++----- 1 file changed, 127 insertions(+), 31 deletions(-) diff --git a/packages/storage/lib/modular/index.d.ts b/packages/storage/lib/modular/index.d.ts index 2346d9b741..f71d895512 100644 --- a/packages/storage/lib/modular/index.d.ts +++ b/packages/storage/lib/modular/index.d.ts @@ -61,20 +61,13 @@ export declare function getStorage(app?: FirebaseApp): Storage; export declare function getStorage(app?: FirebaseApp, bucketUrl?: string): Storage; export function getStorage(app?: FirebaseApp, bucketUrl?: string): Storage; + /** - * Modify this Storage instance to communicate with the Firebase Storage emulator. - * This must be called synchronously immediately following the first call to firebase.storage(). - * Do not use with production credentials as emulator traffic is not encrypted. - * - * Note: on android, hosts 'localhost' and '127.0.0.1' are automatically remapped to '10.0.2.2' (the - * "host" computer IP address for android emulators) to make the standard development experience easy. - * If you want to use the emulator on a real android device, you will need to specify the actual host - * computer IP address. - * - * @param storage: A reference to the `Storage` instance. - * @param host: emulator host (eg, 'localhost') - * @param port: emulator port (eg, 9199) - * @param options: Storage Emulator options. Web only. + * Connects a {@link Storage} instance to the Firebase Storage emulator. + * @param storage - A reference to the `Storage` instance. + * @param host - Emulator host, e.g., 'localhost'. + * @param port - Emulator port, e.g., 9199. + * @param options - Optional. {@link EmulatorMockTokenOptions} instance. */ export function connectStorageEmulator( storage: Storage, @@ -82,65 +75,123 @@ export function connectStorageEmulator( port: number, options?: EmulatorMockTokenOptions, ): void; + /** - * Returns a new {@link Reference} instance. - * - * #### Example - * - * ```js - * const ref = firebase.storage().ref('cats.gif'); - * ``` - * - * @param path An optional string pointing to a location on the storage bucket. If no path - * is provided, the returned reference will be the bucket root path. + * Creates a {@link Reference} from a given path or URL. + * @param storage - The {@link Storage} instance. + * @param path - Optional. A string pointing to a location within the storage bucket. + * @returns A new {@link Reference}. */ export function ref(storage: Storage, path?: string): Reference; + /** - * Deletes the object at this reference's location. - * - * #### Example - * - * ```js - * const ref = firebase.storage().ref('invertase/logo.png'); - * await ref.delete(); - * ``` + * Deletes the object at the given reference's location. + * @param storageRef - The {@link Reference} to the object to delete. + * @returns A promise that resolves when the delete is complete. */ export function deleteObject(storageRef: Reference): Promise; +/** + * Retrieves the blob at the given reference's location. Throws an error if the object is not found. + * @param storageRef - The {@link Reference} to the object. + * @returns A promise resolving to the Blob. + */ export function getBlob(storageRef: Reference): Promise; +/** + * Retrieves bytes (up to the specified max size) from an object at the given reference's location. + * Throws an error if the object is not found or if the size exceeds the maximum allowed. + * @param storageRef - The {@link Reference} to the object. + * @param maxDownloadSizeBytes - Maximum size in bytes to retrieve. + * @returns A promise resolving to an ArrayBuffer. + */ export function getBytes(storageRef: Reference, maxDownloadSizeBytes: number): Promise; +/** + * Retrieves a long-lived download URL for the object at the given reference's location. + * @param storageRef - The {@link Reference} to the object. + * @returns A promise resolving to the URL string. + */ export function getDownloadURL(storageRef: Reference): Promise; +/** + * Retrieves metadata for the object at the given reference's location. + * @param storageRef - The {@link Reference} to the object. + * @returns A promise resolving to the object's {@link FullMetadata}. + */ export function getMetadata(storageRef: Reference): Promise; +/** + * Retrieves a readable stream for the object at the given reference's location. This API is only available in Node.js. + * @param storageRef - The {@link Reference} to the object. + * @param maxDownloadSizeBytes - Maximum size in bytes to retrieve. + * @returns A NodeJS ReadableStream. + */ export function getStream( storageRef: Reference, maxDownloadSizeBytes: number, ): NodeJS.ReadableStream; +/** + * Lists items and prefixes under the given reference. + * @param storageRef - The {@link Reference} under which to list items. + * @param options - Optional. Configuration for listing. + * @returns A promise resolving to a {@link ListResult}. + */ export function list(storageRef: Reference, options?: ListOptions): Promise; +/** + * Lists all items and prefixes under the given reference. + * @param storageRef - The {@link Reference} under which to list items. + * @returns A promise resolving to a {@link ListResult}. + */ export function listAll(storageRef: Reference): Promise; +/** + * Updates metadata for the object at the given reference. + * @param storageRef - The {@link Reference} to the object. + * @param metadata - The metadata to update. + * @returns A promise resolving to the updated {@link FullMetadata}. + */ export function updateMetadata( storageRef: Reference, metadata: SettableMetadata, ): Promise; +/** + * Uploads data to the object's location at the given reference. The upload is not resumable. + * @param storageRef - The {@link Reference} where the data should be uploaded. + * @param data - The data to upload. + * @param metadata - Optional. Metadata to associate with the uploaded object. + * @returns A promise resolving to a {@link TaskResult}. + */ export function uploadBytes( storageRef: Reference, data: Blob | Uint8Array | ArrayBuffer, metadata?: SettableMetadata, ): Promise; +/** + * Initiates a resumable upload session for the data to the object's location at the given reference. + * @param storageRef - The {@link Reference} where the data should be uploaded. + * @param data - The data to upload. + * @param metadata - Optional. Metadata to associate with the uploaded object. + * @returns A {@link Task} associated with the upload process. + */ export function uploadBytesResumable( storageRef: Reference, data: Blob | Uint8Array | ArrayBuffer, metadata?: SettableMetadata, ): Task; +/** + * Uploads a string to the object's location at the given reference. The string format must be specified. + * @param storageRef - The {@link Reference} where the string should be uploaded. + * @param data - The string data to upload. + * @param format - Optional. The format of the string ('raw', 'base64', 'base64url', 'data_url'). + * @param metadata - Optional. Metadata to associate with the uploaded object. + * @returns A {@link Task} associated with the upload process. + */ export function uploadString( storageRef: Reference, data: string, @@ -148,18 +199,63 @@ export function uploadString( metadata?: SettableMetadata, ): Task; +/** + * Creates a {@link Reference} from a storage bucket URL. + * @param storage - The {@link Storage} instance. + * @param url - A URL pointing to a file or location in a storage bucket. + * @returns A {@link Reference} pointing to the specified URL. + */ export function refFromURL(storage: Storage, url: string): Reference; +/** + * Sets the maximum time in milliseconds to retry operations other than upload and download if a failure occurs. + * @param storage - The {@link Storage} instance. + * @param time - The new maximum operation retry time in milliseconds. + */ export function setMaxOperationRetryTime(storage: Storage, time: number): Promise; +/** + * Sets the maximum time in milliseconds to retry upload operations if a failure occurs. + * @param storage - The {@link Storage} instance. + * @param time - The new maximum upload retry time in milliseconds. + */ export function setMaxUploadRetryTime(storage: Storage, time: number): Promise; +/** + * Puts a file from a local disk onto the storage bucket at the given reference. + * @param storageRef - The {@link Reference} where the file should be uploaded. + * @param filePath - The local file path of the file to upload. + * @param metadata - Optional. Metadata to associate with the uploaded file. + * @returns A {@link Task} associated with the upload process. + */ export function putFile(storageRef: Reference, filePath: string, metadata?: SettableMetadata): Task; +/** + * Downloads a file to the specified local file path on the device. + * @param storageRef - The {@link Reference} from which the file should be downloaded. + * @param filePath - The local file path where the file should be written. + * @returns A {@link Task} associated with the download process. + */ export function writeToFile(storageRef: Reference, filePath: string): Task; +/** + * Returns a gs:// URL for the object at the given reference. + * @param storageRef - The {@link Reference} to the object. + * @returns The URL as a string. + */ export function toString(storageRef: Reference): string; +/** + * Returns a reference to a relative path from the given reference. + * @param storageRef - The {@link Reference} as the base. + * @param path - The relative path from the base reference. + * @returns A new {@link Reference}. + */ export function child(storageRef: Reference, path: string): Reference; +/** + * Sets the maximum time in milliseconds to retry download operations if a failure occurs. + * @param storage - The {@link Storage} instance. + * @param time - The new maximum download retry time in milliseconds. + */ export function setMaxDownloadRetryTime(storage: Storage, time: number): Promise; From 905c97e5142d017e10390130a8a73d2659a6fbe7 Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Mon, 22 Jul 2024 14:27:12 +0100 Subject: [PATCH 4/4] tests: test all modular api --- packages/storage/__tests__/storage.test.ts | 121 ++++++++++++++++++++- packages/storage/lib/index.d.ts | 2 + packages/storage/lib/index.js | 2 +- packages/storage/lib/modular/index.js | 15 ++- 4 files changed, 137 insertions(+), 3 deletions(-) diff --git a/packages/storage/__tests__/storage.test.ts b/packages/storage/__tests__/storage.test.ts index 86957264ff..4688bbd082 100644 --- a/packages/storage/__tests__/storage.test.ts +++ b/packages/storage/__tests__/storage.test.ts @@ -1,6 +1,31 @@ import { describe, expect, it } from '@jest/globals'; -import storage, { firebase } from '../lib'; +import storage, { + firebase, + getStorage, + connectStorageEmulator, + ref, + deleteObject, + getBlob, + getBytes, + getDownloadURL, + getMetadata, + getStream, + list, + listAll, + updateMetadata, + uploadBytes, + uploadBytesResumable, + uploadString, + refFromURL, + setMaxOperationRetryTime, + setMaxUploadRetryTime, + putFile, + writeToFile, + toString, + child, + setMaxDownloadRetryTime, +} from '../lib'; describe('Storage', function () { describe('namespace', function () { @@ -45,4 +70,98 @@ describe('Storage', function () { expect(bar).toEqual(['10.0.2.2', 9000]); }); }); + + describe('modular', function () { + it('`getStorage` function is properly exposed to end user', function () { + expect(getStorage).toBeDefined(); + }); + + it('`connectStorageEmulator` function is properly exposed to end user', function () { + expect(connectStorageEmulator).toBeDefined(); + }); + + it('`ref` function is properly exposed to end user', function () { + expect(ref).toBeDefined(); + }); + + it('`deleteObject` function is properly exposed to end user', function () { + expect(deleteObject).toBeDefined(); + }); + + it('`getBlob` function is properly exposed to end user', function () { + expect(getBlob).toBeDefined(); + }); + + it('`getBytes` function is properly exposed to end user', function () { + expect(getBytes).toBeDefined(); + }); + + it('`getDownloadURL` function is properly exposed to end user', function () { + expect(getDownloadURL).toBeDefined(); + }); + + it('`getMetadata` function is properly exposed to end user', function () { + expect(getMetadata).toBeDefined(); + }); + + it('`getStream` function is properly exposed to end user', function () { + expect(getStream).toBeDefined(); + }); + + it('`list` function is properly exposed to end user', function () { + expect(list).toBeDefined(); + }); + + it('`listAll` function is properly exposed to end user', function () { + expect(listAll).toBeDefined(); + }); + + it('`updateMetadata` function is properly exposed to end user', function () { + expect(updateMetadata).toBeDefined(); + }); + + it('`uploadBytes` function is properly exposed to end user', function () { + expect(uploadBytes).toBeDefined(); + }); + + it('`uploadBytesResumable` function is properly exposed to end user', function () { + expect(uploadBytesResumable).toBeDefined(); + }); + + it('`uploadString` function is properly exposed to end user', function () { + expect(uploadString).toBeDefined(); + }); + + it('`refFromURL` function is properly exposed to end user', function () { + expect(refFromURL).toBeDefined(); + }); + + it('`setMaxOperationRetryTime` function is properly exposed to end user', function () { + expect(setMaxOperationRetryTime).toBeDefined(); + }); + + it('`setMaxUploadRetryTime` function is properly exposed to end user', function () { + expect(setMaxUploadRetryTime).toBeDefined(); + }); + + it('`putFile` function is properly exposed to end user', function () { + expect(putFile).toBeDefined(); + }); + + it('`writeToFile` function is properly exposed to end user', function () { + expect(writeToFile).toBeDefined(); + }); + + it('`toString` function is properly exposed to end user', function () { + expect(toString).toBeDefined(); + }); + + it('`child` function is properly exposed to end user', function () { + expect(child).toBeDefined(); + }); + + it('`setMaxDownloadRetryTime` function is properly exposed to end user', function () { + expect(setMaxDownloadRetryTime).toBeDefined(); + }); + }); }); diff --git a/packages/storage/lib/index.d.ts b/packages/storage/lib/index.d.ts index 35fc9d2371..e52378b72a 100644 --- a/packages/storage/lib/index.d.ts +++ b/packages/storage/lib/index.d.ts @@ -1172,3 +1172,5 @@ declare module '@react-native-firebase/app' { } } } + +export * from './modular'; diff --git a/packages/storage/lib/index.js b/packages/storage/lib/index.js index 850ce06e54..c63d638caf 100644 --- a/packages/storage/lib/index.js +++ b/packages/storage/lib/index.js @@ -208,6 +208,6 @@ export default createModuleNamespace({ // firebase.storage().X(...); export const firebase = getFirebaseRoot(); -export * from './modular/index'; +export * from './modular'; setReactNativeModule(nativeModuleName, fallBackModule); diff --git a/packages/storage/lib/modular/index.js b/packages/storage/lib/modular/index.js index 6e46ed95d6..b8ccfa29ab 100644 --- a/packages/storage/lib/modular/index.js +++ b/packages/storage/lib/modular/index.js @@ -14,6 +14,19 @@ * limitations under the License. * */ +/** + * @typedef {import('..').FirebaseStorageTypes} FirebaseStorageTypes + * @typedef {import('..').FirebaseStorageTypes.Module} Storage + * @typedef {import('..').FirebaseStorageTypes.Reference} Reference + * @typedef {import('..').FirebaseStorageTypes.FullMetadata} FullMetadata + * @typedef {import('..').FirebaseStorageTypes.ListResult} ListResult + * @typedef {import('..').FirebaseStorageTypes.TaskResult} TaskResult + * @typedef {import('..').FirebaseStorageTypes.Task} Task + * @typedef {import('..').FirebaseStorageTypes.ListOptions} ListOptions + * @typedef {import('..').FirebaseStorageTypes.SettableMetadata} SettableMetadata + * @typedef {import('..').FirebaseStorageTypes.EmulatorMockTokenOptions} EmulatorMockTokenOptions + * @typedef {import('@firebase/app').FirebaseApp} FirebaseApp + */ import { firebase } from '..'; @@ -56,7 +69,7 @@ export function connectStorageEmulator(storage, host, port, options) { * @param storage - Storage instance. * @param path An optional string pointing to a location on the storage bucket. If no path * is provided, the returned reference will be the bucket root path. Optional. - * @returns {Storage.Reference} + * @returns {Reference} */ export function ref(storage, path) { return storage.ref(path);