1 | import * as React from 'react';
|
2 |
|
3 | import type { AppCheck } from 'firebase/app-check';
|
4 | import type { Auth } from 'firebase/auth';
|
5 | import type { Analytics } from 'firebase/analytics';
|
6 | import type { Database } from 'firebase/database';
|
7 | import type { Firestore } from 'firebase/firestore';
|
8 | import type { Functions } from 'firebase/functions';
|
9 | import type { FirebasePerformance } from 'firebase/performance';
|
10 | import type { FirebaseStorage } from 'firebase/storage';
|
11 | import type { RemoteConfig } from 'firebase/remote-config';
|
12 | import { useFirebaseApp } from './firebaseApp';
|
13 | import { FirebaseApp } from 'firebase/app';
|
14 | import { ObservableStatus, useObservable } from './useObservable';
|
15 | import { from } from 'rxjs';
|
16 | import { ReactFireOptions } from '.';
|
17 |
|
18 | export const AppCheckSdkContext = React.createContext<AppCheck | undefined>(undefined);
|
19 | export const AuthSdkContext = React.createContext<Auth | undefined>(undefined);
|
20 | export const AnalyticsSdkContext = React.createContext<Analytics | undefined>(undefined);
|
21 | export const DatabaseSdkContext = React.createContext<Database | undefined>(undefined);
|
22 | export const FirestoreSdkContext = React.createContext<Firestore | undefined>(undefined);
|
23 | export const FunctionsSdkContext = React.createContext<Functions | undefined>(undefined);
|
24 | export const StorageSdkContext = React.createContext<FirebaseStorage | undefined>(undefined);
|
25 | export const PerformanceSdkContext = React.createContext<FirebasePerformance | undefined>(undefined);
|
26 | export const RemoteConfigSdkContext = React.createContext<RemoteConfig | undefined>(undefined);
|
27 |
|
28 | type FirebaseSdks = Analytics | AppCheck | Auth | Database | Firestore | FirebasePerformance | FirebaseStorage | Functions | RemoteConfig;
|
29 |
|
30 | function getSdkProvider<Sdk extends FirebaseSdks>(SdkContext: React.Context<Sdk | undefined>) {
|
31 | return function SdkProvider(props: React.PropsWithChildren<{ sdk: Sdk }>) {
|
32 | if (!props.sdk) throw new Error('no sdk provided');
|
33 |
|
34 | const contextualAppName = useFirebaseApp().name;
|
35 | const sdkAppName = props?.sdk?.app?.name;
|
36 | if (sdkAppName !== contextualAppName) throw new Error('sdk was initialized with a different firebase app');
|
37 |
|
38 | return <SdkContext.Provider value={props.sdk} {...props} />;
|
39 | };
|
40 | }
|
41 |
|
42 | function useSdk<Sdk extends FirebaseSdks>(SdkContext: React.Context<Sdk | undefined>): Sdk {
|
43 | const sdk = React.useContext(SdkContext);
|
44 |
|
45 | if (!sdk) {
|
46 | throw new Error('SDK not found. useSdk must be called from within a provider');
|
47 | }
|
48 |
|
49 | return sdk;
|
50 | }
|
51 |
|
52 | function useInitSdk<Sdk extends FirebaseSdks>(
|
53 | sdkName: string,
|
54 | SdkContext: React.Context<Sdk | undefined>,
|
55 | sdkInitializer: (firebaseApp: FirebaseApp) => Promise<Sdk>,
|
56 | options?: ReactFireOptions
|
57 | ) {
|
58 | const firebaseApp = useFirebaseApp();
|
59 |
|
60 |
|
61 |
|
62 |
|
63 | if (React.useContext(SdkContext)) {
|
64 | throw new Error(`Cannot initialize SDK ${sdkName} because it already exists in Context`);
|
65 | }
|
66 |
|
67 | const initializeSdk = React.useMemo(() => sdkInitializer(firebaseApp), [firebaseApp]);
|
68 |
|
69 | return useObservable<Sdk>(`firebase-sdk:${sdkName}:${firebaseApp.name}`, from(initializeSdk), options);
|
70 | }
|
71 |
|
72 | export const AppCheckProvider = getSdkProvider<AppCheck>(AppCheckSdkContext);
|
73 | export const AuthProvider = getSdkProvider<Auth>(AuthSdkContext);
|
74 | export const AnalyticsProvider = getSdkProvider<Analytics>(AnalyticsSdkContext);
|
75 | export const DatabaseProvider = getSdkProvider<Database>(DatabaseSdkContext);
|
76 | export const FirestoreProvider = getSdkProvider<Firestore>(FirestoreSdkContext);
|
77 | export const FunctionsProvider = getSdkProvider<Functions>(FunctionsSdkContext);
|
78 | export const PerformanceProvider = getSdkProvider<FirebasePerformance>(PerformanceSdkContext);
|
79 | export const StorageProvider = getSdkProvider<FirebaseStorage>(StorageSdkContext);
|
80 | export const RemoteConfigProvider = getSdkProvider<RemoteConfig>(RemoteConfigSdkContext);
|
81 |
|
82 | export const useAppCheck = () => useSdk<AppCheck>(AppCheckSdkContext);
|
83 | export const useAuth = () => useSdk<Auth>(AuthSdkContext);
|
84 | export const useAnalytics = () => useSdk<Analytics>(AnalyticsSdkContext);
|
85 | export const useDatabase = () => useSdk<Database>(DatabaseSdkContext);
|
86 | export const useFirestore = () => useSdk<Firestore>(FirestoreSdkContext);
|
87 | export const useFunctions = () => useSdk<Functions>(FunctionsSdkContext);
|
88 | export const usePerformance = () => useSdk<FirebasePerformance>(PerformanceSdkContext);
|
89 | export const useStorage = () => useSdk<FirebaseStorage>(StorageSdkContext);
|
90 | export const useRemoteConfig = () => useSdk<RemoteConfig>(RemoteConfigSdkContext);
|
91 |
|
92 | type InitSdkHook<Sdk extends FirebaseSdks> = (
|
93 | initializer: (firebaseApp: FirebaseApp) => Promise<Sdk>,
|
94 | options?: ReactFireOptions<Sdk>
|
95 | ) => ObservableStatus<Sdk>;
|
96 |
|
97 | export const useInitAppCheck: InitSdkHook<AppCheck> = (initializer, options) => useInitSdk<AppCheck>('appcheck', AppCheckSdkContext, initializer, options);
|
98 | export const useInitAuth: InitSdkHook<Auth> = (initializer, options) => useInitSdk<Auth>('auth', AuthSdkContext, initializer, options);
|
99 | export const useInitAnalytics: InitSdkHook<Analytics> = (initializer, options) => useInitSdk<Analytics>('analytics', AnalyticsSdkContext, initializer, options);
|
100 | export const useInitDatabase: InitSdkHook<Database> = (initializer, options) => useInitSdk<Database>('database', DatabaseSdkContext, initializer, options);
|
101 | export const useInitFirestore: InitSdkHook<Firestore> = (initializer, options) => useInitSdk<Firestore>('firestore', FirestoreSdkContext, initializer, options);
|
102 | export const useInitFunctions: InitSdkHook<Functions> = (initializer, options) => useInitSdk<Functions>('functions', FunctionsSdkContext, initializer, options);
|
103 | export const useInitPerformance: InitSdkHook<FirebasePerformance> = (initializer, options) =>
|
104 | useInitSdk<FirebasePerformance>('performance', PerformanceSdkContext, initializer, options);
|
105 | export const useInitRemoteConfig: InitSdkHook<RemoteConfig> = (initializer, options) =>
|
106 | useInitSdk<RemoteConfig>('remoteconfig', RemoteConfigSdkContext, initializer, options);
|
107 | export const useInitStorage: InitSdkHook<FirebaseStorage> = (initializer, options) =>
|
108 | useInitSdk<FirebaseStorage>('storage', StorageSdkContext, initializer, options);
|