Skip to content

Commit aa37ee6

Browse files
committed
Migrate Database to component framework
1 parent 2eec800 commit aa37ee6

File tree

13 files changed

+194
-115
lines changed

13 files changed

+194
-115
lines changed

packages/app-types/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,4 @@ export interface FirebaseNamespace {
102102

103103
// The current SDK version.
104104
SDK_VERSION: string;
105-
}
105+
}

packages/app/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const initializeApp = firebaseNamespace.initializeApp;
4444
// TODO: This disable can be removed and the 'ignoreRestArgs' option added to
4545
// the no-explicit-any rule when ESlint releases it.
4646
// eslint-disable-next-line @typescript-eslint/no-explicit-any
47-
firebaseNamespace.initializeApp = function(...args: any) {
47+
firebaseNamespace.initializeApp = function (...args: any) {
4848
// Environment check before initializing app
4949
// Do the check in initializeApp, so people have a chance to disable it by setting logLevel
5050
// in @firebase/logger

packages/app/src/firebaseNamespaceCore.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ export function createFirebaseNamespaceCore(
213213
// TODO: The eslint disable can be removed and the 'ignoreRestArgs'
214214
// option added to the no-explicit-any rule when ESlint releases it.
215215
// eslint-disable-next-line @typescript-eslint/no-explicit-any
216-
function(...args: any) {
216+
function (...args: any) {
217217
const serviceFxn = this._getService.bind(this, componentName);
218218
return serviceFxn.apply(
219219
this,

packages/app/test/firebaseApp.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ function firebaseAppTests(
315315
}
316316

317317
class TestService implements FirebaseService {
318-
constructor(private app_: FirebaseApp, public instanceIdentifier?: string) {}
318+
constructor(private app_: FirebaseApp, public instanceIdentifier?: string) { }
319319

320320
// TODO(koss): Shouldn't this just be an added method on
321321
// the service instance?
@@ -342,4 +342,4 @@ function createTestComponent(
342342
);
343343
component.setMultipleInstances(multiInstances);
344344
return component;
345-
}
345+
}

packages/auth/src/exports_auth.js

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -616,11 +616,11 @@ fireauth.exportlib.exportFunction(
616616
fireauth.ActionCodeURL.parseLink, [fireauth.args.string('link')]);
617617

618618

619-
(function() {
619+
(function () {
620620
if (typeof firebase === 'undefined' || !firebase.INTERNAL ||
621621
!firebase.INTERNAL.registerComponent) {
622622
throw new Error('Cannot find the firebase namespace; be sure to include ' +
623-
'firebase-app.js before this library.');
623+
'firebase-app.js before this library.');
624624
} else {
625625
var namespace = {
626626
// Exports firebase.auth.ActionCodeInfo.Operation.
@@ -637,36 +637,36 @@ fireauth.exportlib.exportFunction(
637637
'Error': fireauth.AuthError
638638
};
639639
fireauth.exportlib.exportFunction(namespace,
640-
'EmailAuthProvider', fireauth.EmailAuthProvider, []);
640+
'EmailAuthProvider', fireauth.EmailAuthProvider, []);
641641
fireauth.exportlib.exportFunction(namespace,
642-
'FacebookAuthProvider', fireauth.FacebookAuthProvider, []);
642+
'FacebookAuthProvider', fireauth.FacebookAuthProvider, []);
643643
fireauth.exportlib.exportFunction(namespace,
644-
'GithubAuthProvider', fireauth.GithubAuthProvider, []);
644+
'GithubAuthProvider', fireauth.GithubAuthProvider, []);
645645
fireauth.exportlib.exportFunction(namespace,
646-
'GoogleAuthProvider', fireauth.GoogleAuthProvider, []);
646+
'GoogleAuthProvider', fireauth.GoogleAuthProvider, []);
647647
fireauth.exportlib.exportFunction(namespace,
648-
'TwitterAuthProvider', fireauth.TwitterAuthProvider, []);
648+
'TwitterAuthProvider', fireauth.TwitterAuthProvider, []);
649649
fireauth.exportlib.exportFunction(namespace,
650-
'OAuthProvider', fireauth.OAuthProvider, [
651-
fireauth.args.string('providerId')
652-
]);
650+
'OAuthProvider', fireauth.OAuthProvider, [
651+
fireauth.args.string('providerId')
652+
]);
653653
fireauth.exportlib.exportFunction(namespace,
654-
'SAMLAuthProvider', fireauth.SAMLAuthProvider, [
655-
fireauth.args.string('providerId')
656-
]);
654+
'SAMLAuthProvider', fireauth.SAMLAuthProvider, [
655+
fireauth.args.string('providerId')
656+
]);
657657
fireauth.exportlib.exportFunction(namespace,
658-
'PhoneAuthProvider', fireauth.PhoneAuthProvider, [
659-
fireauth.args.firebaseAuth(true)
660-
]);
658+
'PhoneAuthProvider', fireauth.PhoneAuthProvider, [
659+
fireauth.args.firebaseAuth(true)
660+
]);
661661
fireauth.exportlib.exportFunction(namespace,
662-
'RecaptchaVerifier', fireauth.RecaptchaVerifier, [
663-
fireauth.args.or(
664-
fireauth.args.string(),
665-
fireauth.args.element(),
666-
'recaptchaContainer'),
667-
fireauth.args.object('recaptchaParameters', true),
668-
fireauth.args.firebaseApp(true)
669-
]);
662+
'RecaptchaVerifier', fireauth.RecaptchaVerifier, [
663+
fireauth.args.or(
664+
fireauth.args.string(),
665+
fireauth.args.element(),
666+
'recaptchaContainer'),
667+
fireauth.args.object('recaptchaParameters', true),
668+
fireauth.args.firebaseApp(true)
669+
]);
670670
fireauth.exportlib.exportFunction(namespace,
671671
'ActionCodeURL', fireauth.ActionCodeURL, []);
672672

@@ -709,4 +709,4 @@ fireauth.exportlib.exportFunction(
709709
'User': fireauth.AuthUser
710710
});
711711
}
712-
})();
712+
})();

packages/database/index.node.ts

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*/
1717

1818
import { FirebaseNamespace, FirebaseApp } from '@firebase/app-types';
19-
import { _FirebaseNamespace } from '@firebase/app-types/private';
19+
import { _FirebaseNamespace, _FirebaseApp } from '@firebase/app-types/private';
2020
import { Database } from './src/api/Database';
2121
import { DataSnapshot } from './src/api/DataSnapshot';
2222
import { Query } from './src/api/Query';
@@ -30,6 +30,13 @@ import { setSDKVersion } from './src/core/version';
3030
import { CONSTANTS, isNodeSdk } from '@firebase/util';
3131
import { setWebSocketImpl } from './src/realtime/WebSocketConnection';
3232
import { Client } from 'faye-websocket';
33+
import {
34+
Component,
35+
ComponentType,
36+
Provider,
37+
ComponentContainer
38+
} from '@firebase/component';
39+
import { FirebaseAuthInternal } from '@firebase/auth-interop-types';
3340

3441
setWebSocketImpl(Client);
3542

@@ -51,8 +58,26 @@ export function initStandalone(app: FirebaseApp, url: string, version: string) {
5158
CONSTANTS.NODE_ADMIN = true;
5259
setSDKVersion(version);
5360

61+
/**
62+
* Create a 'auth-internal' component using firebase-admin-node's implementation that implements FirebaseAuthInternal.
63+
* ComponentContainer('database-admin') is just a placeholder that doesn't perform any actual function.
64+
*/
65+
const authProvider = new Provider<FirebaseAuthInternal>(
66+
'auth-internal',
67+
new ComponentContainer('database-admin')
68+
);
69+
authProvider.setComponent(
70+
new Component(
71+
'auth-internal',
72+
// firebase-admin-node's app.INTERNAL implements FirebaseAuthInternal interface
73+
// eslint-disable-next-line @eslint-tslint/no-explicit-any
74+
() => (app as any).INTERNAL,
75+
ComponentType.PRIVATE
76+
)
77+
);
78+
5479
return {
55-
instance: RepoManager.getInstance().databaseFromApp(app, url),
80+
instance: RepoManager.getInstance().databaseFromApp(app, authProvider, url),
5681
namespace: {
5782
Reference,
5883
Query,
@@ -71,22 +96,37 @@ export function registerDatabase(instance: FirebaseNamespace) {
7196
setSDKVersion(instance.SDK_VERSION);
7297

7398
// Register the Database Service with the 'firebase' namespace.
74-
const namespace = (instance as _FirebaseNamespace).INTERNAL.registerService(
75-
'database',
76-
(app, unused, url) => RepoManager.getInstance().databaseFromApp(app, url),
77-
// firebase.database namespace properties
78-
{
79-
Reference,
80-
Query,
81-
Database,
82-
DataSnapshot,
83-
enableLogging,
84-
INTERNAL,
85-
ServerValue,
86-
TEST_ACCESS
87-
},
88-
null,
89-
true
99+
const namespace = (instance as _FirebaseNamespace).INTERNAL.registerComponent(
100+
new Component(
101+
'database',
102+
(container, url) => {
103+
/* Dependencies */
104+
// getImmediate for FirebaseApp will always succeed
105+
const app = container.getProvider('app').getImmediate();
106+
const authProvider = container.getProvider('auth-internal');
107+
108+
return RepoManager.getInstance().databaseFromApp(
109+
app,
110+
authProvider,
111+
url
112+
);
113+
},
114+
ComponentType.PUBLIC
115+
)
116+
.setServiceProps(
117+
// firebase.database namespace properties
118+
{
119+
Reference,
120+
Query,
121+
Database,
122+
DataSnapshot,
123+
enableLogging,
124+
INTERNAL,
125+
ServerValue,
126+
TEST_ACCESS
127+
}
128+
)
129+
.setMultipleInstances(true)
90130
);
91131

92132
if (isNodeSdk()) {

packages/database/index.ts

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import * as TEST_ACCESS from './src/api/test_access';
2929
import { isNodeSdk } from '@firebase/util';
3030
import * as types from '@firebase/database-types';
3131
import { setSDKVersion } from './src/core/version';
32+
import { Component, ComponentType } from '@firebase/component';
3233

3334
const ServerValue = Database.ServerValue;
3435

@@ -37,22 +38,39 @@ export function registerDatabase(instance: FirebaseNamespace) {
3738
setSDKVersion(instance.SDK_VERSION);
3839

3940
// Register the Database Service with the 'firebase' namespace.
40-
const namespace = (instance as _FirebaseNamespace).INTERNAL.registerService(
41-
'database',
42-
(app, unused, url) => RepoManager.getInstance().databaseFromApp(app, url),
43-
// firebase.database namespace properties
44-
{
45-
Reference,
46-
Query,
47-
Database,
48-
DataSnapshot,
49-
enableLogging,
50-
INTERNAL,
51-
ServerValue,
52-
TEST_ACCESS
53-
},
54-
null,
55-
true
41+
const namespace = (instance as _FirebaseNamespace).INTERNAL.registerComponent(
42+
new Component(
43+
'database',
44+
(container, url) => {
45+
/* Dependencies */
46+
// getImmediate for FirebaseApp will always succeed
47+
const app = container
48+
.getProvider('app')
49+
.getImmediate(undefined, { optional: true });
50+
const authProvider = container.getProvider('auth-internal');
51+
52+
return RepoManager.getInstance().databaseFromApp(
53+
app,
54+
authProvider,
55+
url
56+
);
57+
},
58+
ComponentType.PUBLIC
59+
)
60+
.setServiceProps(
61+
// firebase.database namespace properties
62+
{
63+
Reference,
64+
Query,
65+
Database,
66+
DataSnapshot,
67+
enableLogging,
68+
INTERNAL,
69+
ServerValue,
70+
TEST_ACCESS
71+
}
72+
)
73+
.setMultipleInstances(true)
5674
);
5775

5876
if (isNodeSdk()) {

packages/database/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"test": "yarn test:emulator",
1717
"test:all": "run-p test:browser test:node",
1818
"test:browser": "karma start --single-run",
19-
"test:node": "TS_NODE_CACHE=NO TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha 'test/{,!(browser)/**/}*.test.ts' --file index.node.ts --opts ../../config/mocha.node.opts",
19+
"test:node": "TS_NODE_FILES=true TS_NODE_CACHE=NO TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha 'test/{,!(browser)/**/}*.test.ts' --file index.node.ts --opts ../../config/mocha.node.opts",
2020
"test:emulator": "ts-node --compiler-options='{\"module\":\"commonjs\"}' ../../scripts/emulator-testing/database-test-runner.ts",
2121
"prepare": "yarn build"
2222
},

packages/database/src/core/AuthTokenProvider.ts

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,48 +15,65 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { FirebaseApp } from '@firebase/app-types';
1918
import { FirebaseAuthTokenData } from '@firebase/app-types/private';
19+
import { FirebaseAuthInternal } from '@firebase/auth-interop-types';
20+
import { Provider } from '@firebase/component';
2021
import { log, warn } from './util/util';
22+
import { FirebaseApp } from '@firebase/app-types';
2123

2224
/**
2325
* Abstraction around FirebaseApp's token fetching capabilities.
2426
*/
2527
export class AuthTokenProvider {
26-
/**
27-
* @param {!FirebaseApp} app_
28-
*/
29-
constructor(private app_: FirebaseApp) {}
28+
private auth_: FirebaseAuthInternal | null = null;
29+
constructor(
30+
private app_: FirebaseApp,
31+
private authProvider_: Provider<FirebaseAuthInternal>
32+
) {
33+
this.auth_ = authProvider_.getImmediate(undefined, { optional: true });
34+
if (!this.auth_) {
35+
authProvider_.get().then(auth => (this.auth_ = auth));
36+
}
37+
}
3038

3139
/**
3240
* @param {boolean} forceRefresh
3341
* @return {!Promise<FirebaseAuthTokenData>}
3442
*/
3543
getToken(forceRefresh: boolean): Promise<FirebaseAuthTokenData> {
36-
return this.app_['INTERNAL']['getToken'](forceRefresh).then(
37-
null,
38-
// .catch
39-
function(error) {
40-
// TODO: Need to figure out all the cases this is raised and whether
41-
// this makes sense.
42-
if (error && error.code === 'auth/token-not-initialized') {
43-
log('Got auth/token-not-initialized error. Treating as null token.');
44-
return null;
45-
} else {
46-
return Promise.reject(error);
47-
}
44+
if (!this.auth_) {
45+
return Promise.resolve(null);
46+
}
47+
48+
return this.auth_.getToken(forceRefresh).catch(function(error) {
49+
// TODO: Need to figure out all the cases this is raised and whether
50+
// this makes sense.
51+
if (error && error.code === 'auth/token-not-initialized') {
52+
log('Got auth/token-not-initialized error. Treating as null token.');
53+
return null;
54+
} else {
55+
return Promise.reject(error);
4856
}
49-
);
57+
});
5058
}
5159

5260
addTokenChangeListener(listener: (token: string | null) => void) {
5361
// TODO: We might want to wrap the listener and call it with no args to
5462
// avoid a leaky abstraction, but that makes removing the listener harder.
55-
this.app_['INTERNAL']['addAuthTokenListener'](listener);
63+
if (this.auth_) {
64+
this.auth_.addAuthTokenListener(listener);
65+
} else {
66+
setTimeout(() => listener(null), 0);
67+
this.authProvider_
68+
.get()
69+
.then(auth => auth.addAuthTokenListener(listener));
70+
}
5671
}
5772

5873
removeTokenChangeListener(listener: (token: string | null) => void) {
59-
this.app_['INTERNAL']['removeAuthTokenListener'](listener);
74+
this.authProvider_
75+
.get()
76+
.then(auth => auth.removeAuthTokenListener(listener));
6077
}
6178

6279
notifyForInvalidToken() {

0 commit comments

Comments
 (0)