reactfire 4.0.0-exp.b6c8eeb → 4.0.0-exp.f654109
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/README.md +5 -3
- package/dist/SuspenseSubject.d.ts +1 -1
- package/dist/functions.d.ts +12 -0
- package/dist/index.d.ts +1 -0
- package/dist/reactfire.cjs.development.js +122 -177
- package/dist/reactfire.cjs.development.js.map +1 -1
- package/dist/reactfire.cjs.production.min.js +1 -1
- package/dist/reactfire.cjs.production.min.js.map +1 -1
- package/dist/reactfire.esm.js +105 -176
- package/dist/reactfire.esm.js.map +1 -1
- package/dist/{remote-config/index.d.ts → remote-config.d.ts} +2 -7
- package/dist/sdk.d.ts +22 -1
- package/package.json +7 -5
- package/src/SuspenseSubject.ts +6 -4
- package/src/firebaseApp.tsx +1 -1
- package/src/functions.tsx +26 -0
- package/src/index.ts +1 -0
- package/src/{remote-config/index.tsx → remote-config.tsx} +4 -16
- package/src/sdk.tsx +22 -28
- package/src/storage.tsx +2 -24
- package/src/useObservable.ts +48 -28
- package/dist/remote-config/getValue.d.ts +0 -10
- package/src/remote-config/getValue.tsx +0 -58
|
@@ -1,35 +1,30 @@
|
|
|
1
|
-
import { ObservableStatus } from '
|
|
2
|
-
import { AllParameters } from '
|
|
1
|
+
import { ObservableStatus } from './useObservable';
|
|
2
|
+
import { AllParameters } from 'rxfire/remote-config';
|
|
3
3
|
import type { Value as RemoteConfigValue } from 'firebase/remote-config';
|
|
4
4
|
/**
|
|
5
5
|
* Accepts a key and optionally a Remote Config instance. Returns a
|
|
6
6
|
* Remote Config Value.
|
|
7
7
|
*
|
|
8
8
|
* @param key The parameter key in Remote Config
|
|
9
|
-
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
|
|
10
9
|
*/
|
|
11
10
|
export declare function useRemoteConfigValue(key: string): ObservableStatus<RemoteConfigValue>;
|
|
12
11
|
/**
|
|
13
12
|
* Convience method similar to useRemoteConfigValue. Returns a `string` from a Remote Config parameter.
|
|
14
13
|
* @param key The parameter key in Remote Config
|
|
15
|
-
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
|
|
16
14
|
*/
|
|
17
15
|
export declare function useRemoteConfigString(key: string): ObservableStatus<string>;
|
|
18
16
|
/**
|
|
19
17
|
* Convience method similar to useRemoteConfigValue. Returns a `number` from a Remote Config parameter.
|
|
20
18
|
* @param key The parameter key in Remote Config
|
|
21
|
-
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
|
|
22
19
|
*/
|
|
23
20
|
export declare function useRemoteConfigNumber(key: string): ObservableStatus<number>;
|
|
24
21
|
/**
|
|
25
22
|
* Convience method similar to useRemoteConfigValue. Returns a `boolean` from a Remote Config parameter.
|
|
26
23
|
* @param key The parameter key in Remote Config
|
|
27
|
-
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
|
|
28
24
|
*/
|
|
29
25
|
export declare function useRemoteConfigBoolean(key: string): ObservableStatus<boolean>;
|
|
30
26
|
/**
|
|
31
27
|
* Convience method similar to useRemoteConfigValue. Returns allRemote Config parameters.
|
|
32
28
|
* @param key The parameter key in Remote Config
|
|
33
|
-
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
|
|
34
29
|
*/
|
|
35
30
|
export declare function useRemoteConfigAll(key: string): ObservableStatus<AllParameters>;
|
package/dist/sdk.d.ts
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import type { AppCheck } from 'firebase/app-check';
|
|
2
3
|
import type { Auth } from 'firebase/auth';
|
|
3
4
|
import type { Analytics } from 'firebase/analytics';
|
|
4
5
|
import type { Database } from 'firebase/database';
|
|
5
6
|
import type { Firestore } from 'firebase/firestore';
|
|
7
|
+
import type { Functions } from 'firebase/functions';
|
|
6
8
|
import type { FirebasePerformance } from 'firebase/performance';
|
|
7
9
|
import type { FirebaseStorage } from 'firebase/storage';
|
|
8
10
|
import type { RemoteConfig } from 'firebase/remote-config';
|
|
9
11
|
import { FirebaseApp } from 'firebase/app';
|
|
10
12
|
import { ObservableStatus } from './useObservable';
|
|
11
13
|
import { ReactFireOptions } from '.';
|
|
12
|
-
declare
|
|
14
|
+
export declare const AppCheckSdkContext: React.Context<AppCheck | undefined>;
|
|
15
|
+
export declare const AuthSdkContext: React.Context<Auth | undefined>;
|
|
16
|
+
export declare const AnalyticsSdkContext: React.Context<Analytics | undefined>;
|
|
17
|
+
export declare const DatabaseSdkContext: React.Context<Database | undefined>;
|
|
18
|
+
export declare const FirestoreSdkContext: React.Context<Firestore | undefined>;
|
|
19
|
+
export declare const FunctionsSdkContext: React.Context<Functions | undefined>;
|
|
20
|
+
export declare const StorageSdkContext: React.Context<FirebaseStorage | undefined>;
|
|
21
|
+
export declare const PerformanceSdkContext: React.Context<FirebasePerformance | undefined>;
|
|
22
|
+
export declare const RemoteConfigSdkContext: React.Context<RemoteConfig | undefined>;
|
|
23
|
+
declare type FirebaseSdks = Analytics | AppCheck | Auth | Database | Firestore | FirebasePerformance | FirebaseStorage | Functions | RemoteConfig;
|
|
24
|
+
export declare const AppCheckProvider: (props: React.PropsWithChildren<{
|
|
25
|
+
sdk: AppCheck;
|
|
26
|
+
}>) => JSX.Element;
|
|
13
27
|
export declare const AuthProvider: (props: React.PropsWithChildren<{
|
|
14
28
|
sdk: Auth;
|
|
15
29
|
}>) => JSX.Element;
|
|
@@ -22,6 +36,9 @@ export declare const DatabaseProvider: (props: React.PropsWithChildren<{
|
|
|
22
36
|
export declare const FirestoreProvider: (props: React.PropsWithChildren<{
|
|
23
37
|
sdk: Firestore;
|
|
24
38
|
}>) => JSX.Element;
|
|
39
|
+
export declare const FunctionsProvider: (props: React.PropsWithChildren<{
|
|
40
|
+
sdk: Functions;
|
|
41
|
+
}>) => JSX.Element;
|
|
25
42
|
export declare const PerformanceProvider: (props: React.PropsWithChildren<{
|
|
26
43
|
sdk: FirebasePerformance;
|
|
27
44
|
}>) => JSX.Element;
|
|
@@ -31,18 +48,22 @@ export declare const StorageProvider: (props: React.PropsWithChildren<{
|
|
|
31
48
|
export declare const RemoteConfigProvider: (props: React.PropsWithChildren<{
|
|
32
49
|
sdk: RemoteConfig;
|
|
33
50
|
}>) => JSX.Element;
|
|
51
|
+
export declare const useAppCheck: () => AppCheck;
|
|
34
52
|
export declare const useAuth: () => Auth;
|
|
35
53
|
export declare const useAnalytics: () => Analytics;
|
|
36
54
|
export declare const useDatabase: () => Database;
|
|
37
55
|
export declare const useFirestore: () => Firestore;
|
|
56
|
+
export declare const useFunctions: () => Functions;
|
|
38
57
|
export declare const usePerformance: () => FirebasePerformance;
|
|
39
58
|
export declare const useStorage: () => FirebaseStorage;
|
|
40
59
|
export declare const useRemoteConfig: () => RemoteConfig;
|
|
41
60
|
declare type InitSdkHook<Sdk extends FirebaseSdks> = (initializer: (firebaseApp: FirebaseApp) => Promise<Sdk>, options?: ReactFireOptions<Sdk>) => ObservableStatus<Sdk>;
|
|
61
|
+
export declare const useInitAppCheck: InitSdkHook<AppCheck>;
|
|
42
62
|
export declare const useInitAuth: InitSdkHook<Auth>;
|
|
43
63
|
export declare const useInitAnalytics: InitSdkHook<Analytics>;
|
|
44
64
|
export declare const useInitDatabase: InitSdkHook<Database>;
|
|
45
65
|
export declare const useInitFirestore: InitSdkHook<Firestore>;
|
|
66
|
+
export declare const useInitFunctions: InitSdkHook<Functions>;
|
|
46
67
|
export declare const useInitPerformance: InitSdkHook<FirebasePerformance>;
|
|
47
68
|
export declare const useInitRemoteConfig: InitSdkHook<RemoteConfig>;
|
|
48
69
|
export declare const useInitStorage: InitSdkHook<FirebaseStorage>;
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.0.0-exp.
|
|
2
|
+
"version": "4.0.0-exp.f654109",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"typings": "dist/index.d.ts",
|
|
@@ -14,16 +14,18 @@
|
|
|
14
14
|
"start": "tsdx watch",
|
|
15
15
|
"build": "tsdx build",
|
|
16
16
|
"test:tsdx": "tsdx test",
|
|
17
|
-
"test": "firebase emulators:exec --
|
|
17
|
+
"test": "firebase emulators:exec --project=rxfire-525a3 \"tsdx test\"",
|
|
18
18
|
"test:firestore": "firebase emulators:exec --only firestore --project=rxfire-525a3 \"tsdx test firestore --verbose\"",
|
|
19
19
|
"test:database": "firebase emulators:exec --only database --project=rxfire-525a3 \"tsdx test database --verbose\"",
|
|
20
20
|
"test:auth": "firebase emulators:exec --only auth --project=rxfire-525a3 \"tsdx test auth --verbose\"",
|
|
21
|
+
"test:functions": "firebase emulators:exec --only functions --project=rxfire-525a3 \"tsdx test functions --verbose\"",
|
|
21
22
|
"test:storage": "firebase emulators:exec --only storage --project=rxfire-525a3 \"tsdx test storage --verbose\"",
|
|
22
23
|
"test:useObservable": "tsdx test useObservable --verbose",
|
|
23
24
|
"lint": "tsdx lint src test",
|
|
24
25
|
"size": "size-limit",
|
|
25
26
|
"analyze": "size-limit --why",
|
|
26
|
-
"docs": "typedoc --options typedoc.json && markdown-toc -i docs/use.md"
|
|
27
|
+
"docs": "typedoc --options typedoc.json && markdown-toc -i docs/use.md",
|
|
28
|
+
"docs:fork": "typedoc --options typedoc.json --gitRemote upstream && markdown-toc -i docs/use.md"
|
|
27
29
|
},
|
|
28
30
|
"peerDependencies": {
|
|
29
31
|
"firebase": "^9.0.0",
|
|
@@ -81,7 +83,7 @@
|
|
|
81
83
|
"babel-jest": "^26.6.3",
|
|
82
84
|
"babel-plugin-minify-replace": "^0.5.0",
|
|
83
85
|
"eslint-plugin-no-only-tests": "^2.6.0",
|
|
84
|
-
"firebase": "^9.0.
|
|
86
|
+
"firebase": "^9.0.1",
|
|
85
87
|
"firebase-tools": "^9.16.0",
|
|
86
88
|
"globalthis": "^1.0.1",
|
|
87
89
|
"husky": "^4.3.0",
|
|
@@ -99,7 +101,7 @@
|
|
|
99
101
|
"typescript": "^4.2.4"
|
|
100
102
|
},
|
|
101
103
|
"dependencies": {
|
|
102
|
-
"rxfire": "^6.0.
|
|
104
|
+
"rxfire": "^6.0.2",
|
|
103
105
|
"rxjs": "^6.6.3 || ^7.0.1"
|
|
104
106
|
},
|
|
105
107
|
"resolutions": {
|
package/src/SuspenseSubject.ts
CHANGED
|
@@ -10,9 +10,9 @@ export class SuspenseSubject<T> extends Subject<T> {
|
|
|
10
10
|
private _innerObservable: Observable<T>;
|
|
11
11
|
private _warmupSubscription: Subscription;
|
|
12
12
|
|
|
13
|
-
// @ts-
|
|
13
|
+
// @ts-expect-error: TODO: double check to see if this is an RXJS thing or if we should listen to TS
|
|
14
14
|
private _innerSubscriber: Subscription;
|
|
15
|
-
// @ts-
|
|
15
|
+
// @ts-expect-error: TODO: double check to see if this is an RXJS thing or if we should listen to TS
|
|
16
16
|
private _resolveFirstEmission: () => void;
|
|
17
17
|
|
|
18
18
|
constructor(innerObservable: Observable<T>, private _timeoutWindow: number) {
|
|
@@ -48,14 +48,16 @@ export class SuspenseSubject<T> extends Subject<T> {
|
|
|
48
48
|
return this._hasValue || !!this._error;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
get value(): T
|
|
51
|
+
get value(): T {
|
|
52
52
|
// TODO figure out how to reset the cache here, if I _reset() here before throwing
|
|
53
53
|
// it doesn't seem to work.
|
|
54
54
|
// As it is now, this will burn the cache entry until the timeout fires.
|
|
55
55
|
if (this._error) {
|
|
56
56
|
throw this._error;
|
|
57
|
+
} else if (!this.hasValue) {
|
|
58
|
+
throw Error('Can only get value if SuspenseSubject has a value');
|
|
57
59
|
}
|
|
58
|
-
return this._value;
|
|
60
|
+
return this._value as T;
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
get firstEmission(): Promise<void> {
|
package/src/firebaseApp.tsx
CHANGED
|
@@ -16,7 +16,7 @@ interface FirebaseAppProviderProps {
|
|
|
16
16
|
suspense?: boolean;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
// @ts-
|
|
19
|
+
// @ts-expect-error: "__REACTFIRE_VERSION__" is replaced with actual ReactFire version (see babel.config.js)
|
|
20
20
|
export const version = __REACTFIRE_VERSION__;
|
|
21
21
|
|
|
22
22
|
const shallowEq = (a: { [key: string]: any }, b: { [key: string]: any }) => a === b || [...Object.keys(a), ...Object.keys(b)].every((key) => a[key] === b[key]);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { httpsCallable as rxHttpsCallable } from 'rxfire/functions';
|
|
2
|
+
import { ReactFireOptions, useObservable, ObservableStatus } from './';
|
|
3
|
+
import { useFunctions } from '.';
|
|
4
|
+
|
|
5
|
+
import type { HttpsCallableOptions } from 'firebase/functions';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Calls a callable function.
|
|
9
|
+
*
|
|
10
|
+
* @param functionName - The name of the function to call
|
|
11
|
+
* @param options
|
|
12
|
+
*/
|
|
13
|
+
export function useCallableFunctionResponse<RequestData, ResponseData>(
|
|
14
|
+
functionName: string,
|
|
15
|
+
options?: ReactFireOptions<ResponseData> & {
|
|
16
|
+
httpsCallableOptions?: HttpsCallableOptions;
|
|
17
|
+
data?: RequestData;
|
|
18
|
+
}
|
|
19
|
+
): ObservableStatus<ResponseData> {
|
|
20
|
+
const functions = useFunctions();
|
|
21
|
+
const observableId = `functions:callableResponse:${functionName}:${JSON.stringify(options?.data)}:${JSON.stringify(options?.httpsCallableOptions)}`;
|
|
22
|
+
const obsFactory = rxHttpsCallable<RequestData, ResponseData>(functions, functionName, options?.httpsCallableOptions);
|
|
23
|
+
const observable$ = obsFactory(options?.data);
|
|
24
|
+
|
|
25
|
+
return useObservable(observableId, observable$, options);
|
|
26
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
import { useRemoteConfig } from '
|
|
2
|
-
import { useObservable, ObservableStatus } from '
|
|
3
|
-
import { getValue, getString, getBoolean, getNumber, getAll, AllParameters } from '
|
|
1
|
+
import { useRemoteConfig } from './';
|
|
2
|
+
import { useObservable, ObservableStatus } from './useObservable';
|
|
3
|
+
import { getValue, getString, getBoolean, getNumber, getAll, AllParameters } from 'rxfire/remote-config';
|
|
4
4
|
import { Observable } from 'rxjs';
|
|
5
5
|
|
|
6
6
|
import type { RemoteConfig, Value as RemoteConfigValue } from 'firebase/remote-config';
|
|
7
7
|
|
|
8
8
|
type Getter$<T> = (remoteConfig: RemoteConfig, key: string) => Observable<T>;
|
|
9
9
|
|
|
10
|
-
interface RemoteConfigWithPrivate extends RemoteConfig {
|
|
11
|
-
// This is a private API, assume optional
|
|
12
|
-
_storage?: { appName: string };
|
|
13
|
-
}
|
|
14
|
-
|
|
15
10
|
/**
|
|
16
11
|
* Helper function to construct type safe functions. Since Remote Config has
|
|
17
12
|
* methods that return different types for values, we need to be extra safe
|
|
@@ -23,9 +18,7 @@ interface RemoteConfigWithPrivate extends RemoteConfig {
|
|
|
23
18
|
function useRemoteConfigValue_INTERNAL<T>(key: string, getter: Getter$<T>): ObservableStatus<T> {
|
|
24
19
|
const remoteConfig = useRemoteConfig();
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
// we might need to iterate over the Firebase apps and check for remoteConfig equality? this works for now
|
|
28
|
-
const appName = (remoteConfig as RemoteConfigWithPrivate)._storage?.appName;
|
|
21
|
+
const appName = remoteConfig.app.name;
|
|
29
22
|
const $value = getter(remoteConfig, key);
|
|
30
23
|
|
|
31
24
|
const observableId = `remoteConfig:${key}:${getter.name}:${appName}`;
|
|
@@ -37,7 +30,6 @@ function useRemoteConfigValue_INTERNAL<T>(key: string, getter: Getter$<T>): Obse
|
|
|
37
30
|
* Remote Config Value.
|
|
38
31
|
*
|
|
39
32
|
* @param key The parameter key in Remote Config
|
|
40
|
-
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
|
|
41
33
|
*/
|
|
42
34
|
export function useRemoteConfigValue(key: string): ObservableStatus<RemoteConfigValue> {
|
|
43
35
|
return useRemoteConfigValue_INTERNAL<RemoteConfigValue>(key, getValue);
|
|
@@ -46,7 +38,6 @@ export function useRemoteConfigValue(key: string): ObservableStatus<RemoteConfig
|
|
|
46
38
|
/**
|
|
47
39
|
* Convience method similar to useRemoteConfigValue. Returns a `string` from a Remote Config parameter.
|
|
48
40
|
* @param key The parameter key in Remote Config
|
|
49
|
-
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
|
|
50
41
|
*/
|
|
51
42
|
export function useRemoteConfigString(key: string): ObservableStatus<string> {
|
|
52
43
|
return useRemoteConfigValue_INTERNAL<string>(key, getString);
|
|
@@ -55,7 +46,6 @@ export function useRemoteConfigString(key: string): ObservableStatus<string> {
|
|
|
55
46
|
/**
|
|
56
47
|
* Convience method similar to useRemoteConfigValue. Returns a `number` from a Remote Config parameter.
|
|
57
48
|
* @param key The parameter key in Remote Config
|
|
58
|
-
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
|
|
59
49
|
*/
|
|
60
50
|
export function useRemoteConfigNumber(key: string): ObservableStatus<number> {
|
|
61
51
|
return useRemoteConfigValue_INTERNAL<number>(key, getNumber);
|
|
@@ -64,7 +54,6 @@ export function useRemoteConfigNumber(key: string): ObservableStatus<number> {
|
|
|
64
54
|
/**
|
|
65
55
|
* Convience method similar to useRemoteConfigValue. Returns a `boolean` from a Remote Config parameter.
|
|
66
56
|
* @param key The parameter key in Remote Config
|
|
67
|
-
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
|
|
68
57
|
*/
|
|
69
58
|
export function useRemoteConfigBoolean(key: string): ObservableStatus<boolean> {
|
|
70
59
|
return useRemoteConfigValue_INTERNAL<boolean>(key, getBoolean);
|
|
@@ -73,7 +62,6 @@ export function useRemoteConfigBoolean(key: string): ObservableStatus<boolean> {
|
|
|
73
62
|
/**
|
|
74
63
|
* Convience method similar to useRemoteConfigValue. Returns allRemote Config parameters.
|
|
75
64
|
* @param key The parameter key in Remote Config
|
|
76
|
-
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
|
|
77
65
|
*/
|
|
78
66
|
export function useRemoteConfigAll(key: string): ObservableStatus<AllParameters> {
|
|
79
67
|
return useRemoteConfigValue_INTERNAL<AllParameters>(key, getAll);
|
package/src/sdk.tsx
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
+
import type { AppCheck } from 'firebase/app-check';
|
|
3
4
|
import type { Auth } from 'firebase/auth';
|
|
4
5
|
import type { Analytics } from 'firebase/analytics';
|
|
5
6
|
import type { Database } from 'firebase/database';
|
|
6
7
|
import type { Firestore } from 'firebase/firestore';
|
|
8
|
+
import type { Functions } from 'firebase/functions';
|
|
7
9
|
import type { FirebasePerformance } from 'firebase/performance';
|
|
8
10
|
import type { FirebaseStorage } from 'firebase/storage';
|
|
9
11
|
import type { RemoteConfig } from 'firebase/remote-config';
|
|
@@ -13,39 +15,25 @@ import { ObservableStatus, useObservable } from './useObservable';
|
|
|
13
15
|
import { from } from 'rxjs';
|
|
14
16
|
import { ReactFireOptions } from '.';
|
|
15
17
|
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
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);
|
|
23
27
|
|
|
24
|
-
type FirebaseSdks =
|
|
28
|
+
type FirebaseSdks = Analytics | AppCheck | Auth | Database | Firestore | FirebasePerformance | FirebaseStorage | Functions | RemoteConfig;
|
|
25
29
|
|
|
26
30
|
function getSdkProvider<Sdk extends FirebaseSdks>(SdkContext: React.Context<Sdk | undefined>) {
|
|
27
31
|
return function SdkProvider(props: React.PropsWithChildren<{ sdk: Sdk }>) {
|
|
28
|
-
|
|
29
|
-
let sdkAppName;
|
|
30
|
-
|
|
31
|
-
// @ts-ignore Auth doesn't have field 'app'
|
|
32
|
-
if (props.sdk.app) {
|
|
33
|
-
// @ts-ignore Auth doesn't have field 'app'
|
|
34
|
-
sdkAppName = props.sdk.app.name;
|
|
35
|
-
|
|
36
|
-
// @ts-ignore only Auth has field 'name'
|
|
37
|
-
} else if (props.sdk.name) {
|
|
38
|
-
// @ts-ignore only Auth has field 'name'
|
|
39
|
-
sdkAppName = props.sdk.name;
|
|
40
|
-
}
|
|
32
|
+
if (!props.sdk) throw new Error('no sdk provided');
|
|
41
33
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (!props.sdk) {
|
|
47
|
-
throw new Error('no sdk provided');
|
|
48
|
-
}
|
|
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');
|
|
49
37
|
|
|
50
38
|
return <SdkContext.Provider value={props.sdk} {...props} />;
|
|
51
39
|
};
|
|
@@ -81,18 +69,22 @@ function useInitSdk<Sdk extends FirebaseSdks>(
|
|
|
81
69
|
return useObservable<Sdk>(`firebase-sdk:${sdkName}:${firebaseApp.name}`, from(initializeSdk), options);
|
|
82
70
|
}
|
|
83
71
|
|
|
72
|
+
export const AppCheckProvider = getSdkProvider<AppCheck>(AppCheckSdkContext);
|
|
84
73
|
export const AuthProvider = getSdkProvider<Auth>(AuthSdkContext);
|
|
85
74
|
export const AnalyticsProvider = getSdkProvider<Analytics>(AnalyticsSdkContext);
|
|
86
75
|
export const DatabaseProvider = getSdkProvider<Database>(DatabaseSdkContext);
|
|
87
76
|
export const FirestoreProvider = getSdkProvider<Firestore>(FirestoreSdkContext);
|
|
77
|
+
export const FunctionsProvider = getSdkProvider<Functions>(FunctionsSdkContext);
|
|
88
78
|
export const PerformanceProvider = getSdkProvider<FirebasePerformance>(PerformanceSdkContext);
|
|
89
79
|
export const StorageProvider = getSdkProvider<FirebaseStorage>(StorageSdkContext);
|
|
90
80
|
export const RemoteConfigProvider = getSdkProvider<RemoteConfig>(RemoteConfigSdkContext);
|
|
91
81
|
|
|
82
|
+
export const useAppCheck = () => useSdk<AppCheck>(AppCheckSdkContext);
|
|
92
83
|
export const useAuth = () => useSdk<Auth>(AuthSdkContext);
|
|
93
84
|
export const useAnalytics = () => useSdk<Analytics>(AnalyticsSdkContext);
|
|
94
85
|
export const useDatabase = () => useSdk<Database>(DatabaseSdkContext);
|
|
95
86
|
export const useFirestore = () => useSdk<Firestore>(FirestoreSdkContext);
|
|
87
|
+
export const useFunctions = () => useSdk<Functions>(FunctionsSdkContext);
|
|
96
88
|
export const usePerformance = () => useSdk<FirebasePerformance>(PerformanceSdkContext);
|
|
97
89
|
export const useStorage = () => useSdk<FirebaseStorage>(StorageSdkContext);
|
|
98
90
|
export const useRemoteConfig = () => useSdk<RemoteConfig>(RemoteConfigSdkContext);
|
|
@@ -102,10 +94,12 @@ type InitSdkHook<Sdk extends FirebaseSdks> = (
|
|
|
102
94
|
options?: ReactFireOptions<Sdk>
|
|
103
95
|
) => ObservableStatus<Sdk>;
|
|
104
96
|
|
|
97
|
+
export const useInitAppCheck: InitSdkHook<AppCheck> = (initializer, options) => useInitSdk<AppCheck>('appcheck', AppCheckSdkContext, initializer, options);
|
|
105
98
|
export const useInitAuth: InitSdkHook<Auth> = (initializer, options) => useInitSdk<Auth>('auth', AuthSdkContext, initializer, options);
|
|
106
99
|
export const useInitAnalytics: InitSdkHook<Analytics> = (initializer, options) => useInitSdk<Analytics>('analytics', AnalyticsSdkContext, initializer, options);
|
|
107
100
|
export const useInitDatabase: InitSdkHook<Database> = (initializer, options) => useInitSdk<Database>('database', DatabaseSdkContext, initializer, options);
|
|
108
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);
|
|
109
103
|
export const useInitPerformance: InitSdkHook<FirebasePerformance> = (initializer, options) =>
|
|
110
104
|
useInitSdk<FirebasePerformance>('performance', PerformanceSdkContext, initializer, options);
|
|
111
105
|
export const useInitRemoteConfig: InitSdkHook<RemoteConfig> = (initializer, options) =>
|
package/src/storage.tsx
CHANGED
|
@@ -1,33 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { getDownloadURL } from 'rxfire/storage';
|
|
3
|
-
import { Observable } from 'rxjs';
|
|
2
|
+
import { getDownloadURL, fromTask } from 'rxfire/storage';
|
|
4
3
|
import { ReactFireOptions, useObservable, ObservableStatus, useStorage } from './';
|
|
5
4
|
import { useSuspenseEnabledFromConfigAndContext } from './firebaseApp';
|
|
6
5
|
import { ref } from 'firebase/storage';
|
|
7
6
|
|
|
8
7
|
import type { UploadTask, UploadTaskSnapshot, StorageReference, FirebaseStorage } from 'firebase/storage';
|
|
9
8
|
|
|
10
|
-
/**
|
|
11
|
-
* modified version of rxFire's _fromTask
|
|
12
|
-
*
|
|
13
|
-
* @param task
|
|
14
|
-
*/
|
|
15
|
-
function _fromTask(task: UploadTask) {
|
|
16
|
-
return new Observable<UploadTaskSnapshot>((subscriber) => {
|
|
17
|
-
const progress = (snap: UploadTaskSnapshot) => {
|
|
18
|
-
return subscriber.next(snap);
|
|
19
|
-
};
|
|
20
|
-
const error = (e: any) => subscriber.error(e);
|
|
21
|
-
const complete = () => {
|
|
22
|
-
return subscriber.complete();
|
|
23
|
-
};
|
|
24
|
-
task.on('state_changed', progress, error, complete);
|
|
25
|
-
|
|
26
|
-
// I REMOVED THE UNSUBSCRIBE RETURN BECAUSE IT CANCELS THE UPLOAD
|
|
27
|
-
// https://github.com/firebase/firebase-js-sdk/issues/1659
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
9
|
/**
|
|
32
10
|
* Subscribe to the progress of a storage task
|
|
33
11
|
*
|
|
@@ -37,7 +15,7 @@ function _fromTask(task: UploadTask) {
|
|
|
37
15
|
*/
|
|
38
16
|
export function useStorageTask<T = unknown>(task: UploadTask, ref: StorageReference, options?: ReactFireOptions<T>): ObservableStatus<UploadTaskSnapshot | T> {
|
|
39
17
|
const observableId = `storage:task:${ref.toString()}`;
|
|
40
|
-
const observable$ =
|
|
18
|
+
const observable$ = fromTask(task);
|
|
41
19
|
|
|
42
20
|
return useObservable(observableId, observable$, options);
|
|
43
21
|
}
|
package/src/useObservable.ts
CHANGED
|
@@ -63,55 +63,75 @@ export interface ObservableStatus<T> {
|
|
|
63
63
|
firstValuePromise: Promise<void>;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
function reducerFactory<T>(observable: SuspenseSubject<T>) {
|
|
67
|
+
return function reducer(state: ObservableStatus<T>, action: 'value' | 'error' | 'complete'): ObservableStatus<T> {
|
|
68
|
+
// always make sure these values are in sync with the observable
|
|
69
|
+
const newState = {
|
|
70
|
+
...state,
|
|
71
|
+
hasEmitted: state.hasEmitted || observable.hasValue,
|
|
72
|
+
error: observable.ourError,
|
|
73
|
+
firstValuePromise: observable.firstEmission,
|
|
74
|
+
};
|
|
75
|
+
if (observable.hasValue) {
|
|
76
|
+
newState.data = observable.value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
switch (action) {
|
|
80
|
+
case 'value':
|
|
81
|
+
newState.status = 'success';
|
|
82
|
+
return newState;
|
|
83
|
+
case 'error':
|
|
84
|
+
newState.status = 'error';
|
|
85
|
+
return newState;
|
|
86
|
+
case 'complete':
|
|
87
|
+
newState.isComplete = true;
|
|
88
|
+
return newState;
|
|
89
|
+
default:
|
|
90
|
+
throw new Error(`invalid action "${action}"`);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
66
95
|
export function useObservable<T = unknown>(observableId: string, source: Observable<T>, config: ReactFireOptions = {}): ObservableStatus<T> {
|
|
96
|
+
// Register the observable with the cache
|
|
67
97
|
if (!observableId) {
|
|
68
98
|
throw new Error('cannot call useObservable without an observableId');
|
|
69
99
|
}
|
|
70
100
|
const observable = preloadObservable(source, observableId);
|
|
71
101
|
|
|
102
|
+
// Suspend if suspense is enabled and no initial data exists
|
|
72
103
|
const hasInitialData = config.hasOwnProperty('initialData') || config.hasOwnProperty('startWithValue');
|
|
73
|
-
|
|
104
|
+
const hasData = observable.hasValue || hasInitialData;
|
|
74
105
|
const suspenseEnabled = useSuspenseEnabledFromConfigAndContext(config.suspense);
|
|
75
|
-
|
|
76
|
-
if (suspenseEnabled === true && !observable.hasValue && (!config?.initialData ?? !config?.startWithValue)) {
|
|
106
|
+
if (suspenseEnabled === true && !hasData) {
|
|
77
107
|
throw observable.firstEmission;
|
|
78
108
|
}
|
|
79
109
|
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
110
|
+
const initialState: ObservableStatus<T> = {
|
|
111
|
+
status: hasData ? 'success' : 'loading',
|
|
112
|
+
hasEmitted: hasData,
|
|
113
|
+
isComplete: false,
|
|
114
|
+
data: observable.hasValue ? observable.value : config?.initialData ?? config?.startWithValue,
|
|
115
|
+
error: observable.ourError,
|
|
116
|
+
firstValuePromise: observable.firstEmission,
|
|
117
|
+
};
|
|
118
|
+
const [status, dispatch] = React.useReducer<React.Reducer<ObservableStatus<T>, 'value' | 'error' | 'complete'>>(reducerFactory<T>(observable), initialState);
|
|
119
|
+
|
|
83
120
|
React.useEffect(() => {
|
|
84
121
|
const subscription = observable.subscribe({
|
|
85
|
-
next: (
|
|
86
|
-
|
|
122
|
+
next: () => {
|
|
123
|
+
dispatch('value');
|
|
87
124
|
},
|
|
88
125
|
error: (e) => {
|
|
89
|
-
|
|
126
|
+
dispatch('error');
|
|
90
127
|
throw e;
|
|
91
128
|
},
|
|
92
129
|
complete: () => {
|
|
93
|
-
|
|
130
|
+
dispatch('complete');
|
|
94
131
|
},
|
|
95
132
|
});
|
|
96
133
|
return () => subscription.unsubscribe();
|
|
97
134
|
}, [observable]);
|
|
98
135
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (hasError) {
|
|
102
|
-
status = 'error';
|
|
103
|
-
} else if (observable.hasValue || hasInitialData) {
|
|
104
|
-
status = 'success';
|
|
105
|
-
} else {
|
|
106
|
-
status = 'loading';
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return {
|
|
110
|
-
status,
|
|
111
|
-
hasEmitted: observable.hasValue || hasInitialData,
|
|
112
|
-
isComplete: isComplete,
|
|
113
|
-
data: latest,
|
|
114
|
-
error: observable.ourError,
|
|
115
|
-
firstValuePromise: observable.firstEmission,
|
|
116
|
-
};
|
|
136
|
+
return status;
|
|
117
137
|
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Observable } from 'rxjs';
|
|
2
|
-
import type { RemoteConfig, Value as RemoteConfigValue } from 'firebase/remote-config';
|
|
3
|
-
export declare type AllParameters = {
|
|
4
|
-
[key: string]: RemoteConfigValue;
|
|
5
|
-
};
|
|
6
|
-
export declare function getValue(remoteConfig: RemoteConfig, key: string): Observable<RemoteConfigValue>;
|
|
7
|
-
export declare function getString(remoteConfig: RemoteConfig, key: string): Observable<string>;
|
|
8
|
-
export declare function getNumber(remoteConfig: RemoteConfig, key: string): Observable<number>;
|
|
9
|
-
export declare function getBoolean(remoteConfig: RemoteConfig, key: string): Observable<boolean>;
|
|
10
|
-
export declare function getAll(remoteConfig: RemoteConfig): Observable<AllParameters>;
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { Observable } from 'rxjs';
|
|
2
|
-
import {
|
|
3
|
-
ensureInitialized,
|
|
4
|
-
getValue as rcGetValue,
|
|
5
|
-
getString as rcGetString,
|
|
6
|
-
getNumber as rcGetNumber,
|
|
7
|
-
getBoolean as rcGetBoolean,
|
|
8
|
-
getAll as rcGetAll,
|
|
9
|
-
} from 'firebase/remote-config';
|
|
10
|
-
|
|
11
|
-
import type { RemoteConfig, Value as RemoteConfigValue } from 'firebase/remote-config';
|
|
12
|
-
|
|
13
|
-
export type AllParameters = {
|
|
14
|
-
[key: string]: RemoteConfigValue;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
interface ParameterSettings<T> {
|
|
18
|
-
remoteConfig: RemoteConfig;
|
|
19
|
-
key: string;
|
|
20
|
-
getter: (key: string) => T;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// TODO(davideast): Replace with RxFire functions when they land
|
|
24
|
-
function parameter$<T>({ remoteConfig, key, getter }: ParameterSettings<T>): Observable<T> {
|
|
25
|
-
return new Observable((subscriber) => {
|
|
26
|
-
ensureInitialized(remoteConfig).then(() => {
|
|
27
|
-
// 'this' for the getter loses context in the next()
|
|
28
|
-
// call, so it needs to be bound.
|
|
29
|
-
subscriber.next(getter.bind(remoteConfig)(key));
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function getValue(remoteConfig: RemoteConfig, key: string) {
|
|
35
|
-
const getter = () => rcGetValue(remoteConfig, key);
|
|
36
|
-
return parameter$({ remoteConfig, key, getter });
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function getString(remoteConfig: RemoteConfig, key: string) {
|
|
40
|
-
const getter = () => rcGetString(remoteConfig, key);
|
|
41
|
-
return parameter$<string>({ remoteConfig, key, getter });
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function getNumber(remoteConfig: RemoteConfig, key: string) {
|
|
45
|
-
const getter = () => rcGetNumber(remoteConfig, key);
|
|
46
|
-
return parameter$<number>({ remoteConfig, key, getter });
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function getBoolean(remoteConfig: RemoteConfig, key: string) {
|
|
50
|
-
const getter = () => rcGetBoolean(remoteConfig, key);
|
|
51
|
-
return parameter$<boolean>({ remoteConfig, key, getter });
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function getAll(remoteConfig: RemoteConfig) {
|
|
55
|
-
const getter = () => rcGetAll(remoteConfig);
|
|
56
|
-
// No key is needed for getAll()
|
|
57
|
-
return parameter$<AllParameters>({ remoteConfig, key: '', getter });
|
|
58
|
-
}
|