From 22e78f4c09628ee3746913115a13b721c2bee6c3 Mon Sep 17 00:00:00 2001 From: sujishpatel Date: Fri, 20 Aug 2021 22:23:14 -0400 Subject: [PATCH 01/24] add support for appcheck and analytics --- src/sdk.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sdk.tsx b/src/sdk.tsx index d8faef39..a1557285 100644 --- a/src/sdk.tsx +++ b/src/sdk.tsx @@ -1,5 +1,7 @@ import * as React from 'react'; +import type { Analytics } from 'firebase/analytics'; +import type { AppCheck } from 'firebase/app-check'; import type { Auth } from 'firebase/auth'; import type { Database } from 'firebase/database'; import type { Firestore } from 'firebase/firestore'; @@ -12,6 +14,8 @@ import { ObservableStatus, useObservable } from './useObservable'; import { from } from 'rxjs'; import { ReactFireOptions } from '.'; +const AnalyticsSdkContext = React.createContext(undefined); +const AppCheckSdkContext = React.createContext(undefined); const AuthSdkContext = React.createContext(undefined); const DatabaseSdkContext = React.createContext(undefined); const FirestoreSdkContext = React.createContext(undefined); @@ -19,7 +23,7 @@ const StorageSdkContext = React.createContext(undef const PerformanceSdkContext = React.createContext(undefined); const RemoteConfigSdkContext = React.createContext(undefined); -type FirebaseSdks = Auth | Database | Firestore | FirebasePerformance | FirebaseStorage | RemoteConfig; +type FirebaseSdks = Analytics | AppCheck | Auth | Database | Firestore | FirebasePerformance | FirebaseStorage | RemoteConfig; function getSdkProvider(SdkContext: React.Context) { return function SdkProvider(props: React.PropsWithChildren<{ sdk: Sdk }>) { @@ -79,6 +83,8 @@ function useInitSdk( return useObservable(`firebase-sdk:${sdkName}:${firebaseApp.name}`, from(initializeSdk), options); } +export const AppCheckProvider = getSdkProvider(AppCheckSdkContext); +export const AnalyticsProvider = getSdkProvider(AnalyticsSdkContext); export const AuthProvider = getSdkProvider(AuthSdkContext); export const DatabaseProvider = getSdkProvider(DatabaseSdkContext); export const FirestoreProvider = getSdkProvider(FirestoreSdkContext); @@ -86,6 +92,8 @@ export const PerformanceProvider = getSdkProvider(Performan export const StorageProvider = getSdkProvider(StorageSdkContext); export const RemoteConfigProvider = getSdkProvider(RemoteConfigSdkContext); +export const useAppCheck = () => useSdk(AppCheckSdkContext); +export const useAnalytics = () => useSdk(AnalyticsSdkContext); export const useAuth = () => useSdk(AuthSdkContext); export const useDatabase = () => useSdk(DatabaseSdkContext); export const useFirestore = () => useSdk(FirestoreSdkContext); @@ -98,6 +106,8 @@ type InitSdkHook = ( options?: ReactFireOptions ) => ObservableStatus; +export const useInitAppCheck: InitSdkHook = (initializer, options) => useInitSdk('appcheck', AppCheckSdkContext, initializer, options); +export const useInitAnalytics: InitSdkHook = (initializer, options) => useInitSdk('analytics', AnalyticsSdkContext, initializer, options); export const useInitAuth: InitSdkHook = (initializer, options) => useInitSdk('auth', AuthSdkContext, initializer, options); export const useInitDatabase: InitSdkHook = (initializer, options) => useInitSdk('database', DatabaseSdkContext, initializer, options); export const useInitFirestore: InitSdkHook = (initializer, options) => useInitSdk('firestore', FirestoreSdkContext, initializer, options); From 6ff241758778b77019a7529d552f55659d06ae82 Mon Sep 17 00:00:00 2001 From: sujishpatel Date: Sat, 21 Aug 2021 00:08:19 -0400 Subject: [PATCH 02/24] update remote config to use rxfire --- .../index.tsx => remote-config.tsx} | 6 +- src/remote-config/getValue.tsx | 58 ------------------- 2 files changed, 3 insertions(+), 61 deletions(-) rename src/{remote-config/index.tsx => remote-config.tsx} (95%) delete mode 100644 src/remote-config/getValue.tsx diff --git a/src/remote-config/index.tsx b/src/remote-config.tsx similarity index 95% rename from src/remote-config/index.tsx rename to src/remote-config.tsx index 35f9edd2..5811bbd5 100644 --- a/src/remote-config/index.tsx +++ b/src/remote-config.tsx @@ -1,6 +1,6 @@ -import { useRemoteConfig } from '../'; -import { useObservable, ObservableStatus } from '../useObservable'; -import { getValue, getString, getBoolean, getNumber, getAll, AllParameters } from './getValue'; +import { useRemoteConfig } from './'; +import { useObservable, ObservableStatus } from './useObservable'; +import { getValue, getString, getBoolean, getNumber, getAll, AllParameters } from 'rxfire/remote-config'; import { Observable } from 'rxjs'; import type { RemoteConfig, Value as RemoteConfigValue } from 'firebase/remote-config'; diff --git a/src/remote-config/getValue.tsx b/src/remote-config/getValue.tsx deleted file mode 100644 index 020636f0..00000000 --- a/src/remote-config/getValue.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { Observable } from 'rxjs'; -import { - ensureInitialized, - getValue as rcGetValue, - getString as rcGetString, - getNumber as rcGetNumber, - getBoolean as rcGetBoolean, - getAll as rcGetAll, -} from 'firebase/remote-config'; - -import type { RemoteConfig, Value as RemoteConfigValue } from 'firebase/remote-config'; - -export type AllParameters = { - [key: string]: RemoteConfigValue; -}; - -interface ParameterSettings { - remoteConfig: RemoteConfig; - key: string; - getter: (key: string) => T; -} - -// TODO(davideast): Replace with RxFire functions when they land -function parameter$({ remoteConfig, key, getter }: ParameterSettings): Observable { - return new Observable((subscriber) => { - ensureInitialized(remoteConfig).then(() => { - // 'this' for the getter loses context in the next() - // call, so it needs to be bound. - subscriber.next(getter.bind(remoteConfig)(key)); - }); - }); -} - -export function getValue(remoteConfig: RemoteConfig, key: string) { - const getter = () => rcGetValue(remoteConfig, key); - return parameter$({ remoteConfig, key, getter }); -} - -export function getString(remoteConfig: RemoteConfig, key: string) { - const getter = () => rcGetString(remoteConfig, key); - return parameter$({ remoteConfig, key, getter }); -} - -export function getNumber(remoteConfig: RemoteConfig, key: string) { - const getter = () => rcGetNumber(remoteConfig, key); - return parameter$({ remoteConfig, key, getter }); -} - -export function getBoolean(remoteConfig: RemoteConfig, key: string) { - const getter = () => rcGetBoolean(remoteConfig, key); - return parameter$({ remoteConfig, key, getter }); -} - -export function getAll(remoteConfig: RemoteConfig) { - const getter = () => rcGetAll(remoteConfig); - // No key is needed for getAll() - return parameter$({ remoteConfig, key: '', getter }); -} From 2c9efab34b025498c6d504ab09709dfc83bf672c Mon Sep 17 00:00:00 2001 From: sujishpatel Date: Sat, 21 Aug 2021 18:57:21 -0400 Subject: [PATCH 03/24] remove ts-ignore and listen to rules of hooks --- src/sdk.tsx | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/src/sdk.tsx b/src/sdk.tsx index a1557285..9e4f985b 100644 --- a/src/sdk.tsx +++ b/src/sdk.tsx @@ -7,6 +7,7 @@ import type { Database } from 'firebase/database'; import type { Firestore } from 'firebase/firestore'; import type { FirebasePerformance } from 'firebase/performance'; import type { FirebaseStorage } from 'firebase/storage'; +import type { Functions } from 'firebase/functions'; import type { RemoteConfig } from 'firebase/remote-config'; import { useFirebaseApp } from './firebaseApp'; import { FirebaseApp } from 'firebase/app'; @@ -19,35 +20,25 @@ const AppCheckSdkContext = React.createContext(undefined); const AuthSdkContext = React.createContext(undefined); const DatabaseSdkContext = React.createContext(undefined); const FirestoreSdkContext = React.createContext(undefined); +const FunctionsSdkContext = React.createContext(undefined); const StorageSdkContext = React.createContext(undefined); const PerformanceSdkContext = React.createContext(undefined); const RemoteConfigSdkContext = React.createContext(undefined); -type FirebaseSdks = Analytics | AppCheck | Auth | Database | Firestore | FirebasePerformance | FirebaseStorage | RemoteConfig; +type FirebaseSdks = Analytics | AppCheck | Auth | Database | Firestore | Functions | FirebasePerformance | FirebaseStorage | RemoteConfig; function getSdkProvider(SdkContext: React.Context) { return function SdkProvider(props: React.PropsWithChildren<{ sdk: Sdk }>) { - const contextualAppName = useFirebaseApp().name; - let sdkAppName; - - // @ts-ignore Auth doesn't have field 'app' - if (props.sdk.app) { - // @ts-ignore Auth doesn't have field 'app' - sdkAppName = props.sdk.app.name; + if (!props.sdk) throw new Error('no sdk provided'); - // @ts-ignore only Auth has field 'name' - } else if (props.sdk.name) { - // @ts-ignore only Auth has field 'name' - sdkAppName = props.sdk.name; - } - - if (sdkAppName !== contextualAppName) { - throw new Error('sdk was initialized with a different firebase app'); - } + const contextualAppName = useFirebaseApp().name; + // Based on public type defs: Auth would trigger in the 'name' case and Performance would trigger else case + // Since 'performance' doesn't expose a publically defined way to get the app name, we return "" + // However, in practice all of the sdks have 'sdk.app.name' as a hidden implementation detail, + // so 'performance' won't actually fail the subsequent equality test + const sdkAppName = 'app' in props.sdk && 'name' in props.sdk.app ? props.sdk.app.name : 'name' in props.sdk ? props.sdk.name : ''; - if (!props.sdk) { - throw new Error('no sdk provided'); - } + if (sdkAppName !== contextualAppName) throw new Error('sdk was initialized with a different firebase app'); return ; }; @@ -78,7 +69,7 @@ function useInitSdk( throw new Error(`Cannot initialize SDK ${sdkName} because it already exists in Context`); } - const initializeSdk = React.useMemo(() => sdkInitializer(firebaseApp), [firebaseApp]); + const initializeSdk = React.useMemo(() => sdkInitializer(firebaseApp), [firebaseApp, sdkInitializer]); return useObservable(`firebase-sdk:${sdkName}:${firebaseApp.name}`, from(initializeSdk), options); } @@ -88,6 +79,7 @@ export const AnalyticsProvider = getSdkProvider(AnalyticsSdkContext); export const AuthProvider = getSdkProvider(AuthSdkContext); export const DatabaseProvider = getSdkProvider(DatabaseSdkContext); export const FirestoreProvider = getSdkProvider(FirestoreSdkContext); +export const FunctionsProvider = getSdkProvider(FunctionsSdkContext); export const PerformanceProvider = getSdkProvider(PerformanceSdkContext); export const StorageProvider = getSdkProvider(StorageSdkContext); export const RemoteConfigProvider = getSdkProvider(RemoteConfigSdkContext); @@ -97,6 +89,7 @@ export const useAnalytics = () => useSdk(AnalyticsSdkContext); export const useAuth = () => useSdk(AuthSdkContext); export const useDatabase = () => useSdk(DatabaseSdkContext); export const useFirestore = () => useSdk(FirestoreSdkContext); +export const useFunctions = () => useSdk(FunctionsSdkContext); export const usePerformance = () => useSdk(PerformanceSdkContext); export const useStorage = () => useSdk(StorageSdkContext); export const useRemoteConfig = () => useSdk(RemoteConfigSdkContext); @@ -111,6 +104,7 @@ export const useInitAnalytics: InitSdkHook = (initializer, options) = export const useInitAuth: InitSdkHook = (initializer, options) => useInitSdk('auth', AuthSdkContext, initializer, options); export const useInitDatabase: InitSdkHook = (initializer, options) => useInitSdk('database', DatabaseSdkContext, initializer, options); export const useInitFirestore: InitSdkHook = (initializer, options) => useInitSdk('firestore', FirestoreSdkContext, initializer, options); +export const useInitFunctions: InitSdkHook = (initializer, options) => useInitSdk('functions', FunctionsSdkContext, initializer, options); export const useInitPerformance: InitSdkHook = (initializer, options) => useInitSdk('performance', PerformanceSdkContext, initializer, options); export const useInitRemoteConfig: InitSdkHook = (initializer, options) => From e6cf5c2129250386b39fc30ffa1c3ed82acd86c8 Mon Sep 17 00:00:00 2001 From: sujishpatel Date: Sat, 21 Aug 2021 19:02:53 -0400 Subject: [PATCH 04/24] updated doc with question --- src/sdk.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sdk.tsx b/src/sdk.tsx index 9e4f985b..f543ce4f 100644 --- a/src/sdk.tsx +++ b/src/sdk.tsx @@ -32,10 +32,9 @@ function getSdkProvider(SdkContext: React.Context