Skip to content

Commit

Permalink
Auth explicit initialization (#4714)
Browse files Browse the repository at this point in the history
* Add explicit instantation mode

* implement auth explicit initialization

* Update packages/component/src/types.ts

Co-authored-by: Yuchen Shi <yuchenshi@google.com>

* address comments

* fix typeing error

* fix typings

* fix typings

* fix typings

* Create chatty-cooks-drop.md

* Create stale-zebras-hug.md

Co-authored-by: Yuchen Shi <yuchenshi@google.com>
  • Loading branch information
Feiyang1 and yuchenshi authored Apr 6, 2021
1 parent 318d9bf commit f24d896
Show file tree
Hide file tree
Showing 17 changed files with 232 additions and 77 deletions.
5 changes: 5 additions & 0 deletions .changeset/chatty-cooks-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@firebase/component": minor
---

Support new instantiation mode `EXPLICIT`
7 changes: 7 additions & 0 deletions .changeset/stale-zebras-hug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@firebase/app-types": patch
"@firebase/app": patch
"@firebase/rules-unit-testing": patch
---

Internal typing changes
4 changes: 2 additions & 2 deletions common/api-review/app-exp.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Name } from '@firebase/component';
import { Provider } from '@firebase/component';

// @internal (undocumented)
export function _addComponent(app: FirebaseApp, component: Component): void;
export function _addComponent<T extends Name>(app: FirebaseApp, component: Component<T>): void;

// @internal (undocumented)
export function _addOrOverwriteComponent(app: FirebaseApp, component: Component): void;
Expand Down Expand Up @@ -102,7 +102,7 @@ export function initializeApp(options: FirebaseOptions, config?: FirebaseAppConf
export function onLog(logCallback: LogCallback | null, options?: LogOptions): void;

// @internal (undocumented)
export function _registerComponent(component: Component): boolean;
export function _registerComponent<T extends Name>(component: Component<T>): boolean;

// @public
export function registerVersion(libraryKeyOrName: string, version: string, variant?: string): void;
Expand Down
6 changes: 3 additions & 3 deletions packages-exp/app-compat/src/firebaseNamespaceCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
} from './types';
import * as modularAPIs from '@firebase/app-exp';
import { _FirebaseAppInternal as _FirebaseAppExp } from '@firebase/app-exp';
import { Component, ComponentType } from '@firebase/component';
import { Component, ComponentType, Name } from '@firebase/component';

import { deepExtend, contains } from '@firebase/util';
import { FirebaseAppImpl } from './firebaseApp';
Expand Down Expand Up @@ -131,8 +131,8 @@ export function createFirebaseNamespaceCore(
return Object.keys(apps).map(name => apps[name]);
}

function registerComponentCompat(
component: Component
function registerComponentCompat<T extends Name>(
component: Component<T>
): FirebaseServiceNamespace<_FirebaseService> | null {
const componentName = component.name;
const componentNameWithoutCompat = componentName.replace('-compat', '');
Expand Down
10 changes: 5 additions & 5 deletions packages-exp/app-compat/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

import { FirebaseApp, FirebaseNamespace } from './public-types';
import { Compat } from '@firebase/util';
import { Component, ComponentContainer } from '@firebase/component';
import { Component, ComponentContainer, Name } from '@firebase/component';

export interface FirebaseServiceInternals {
/**
Expand Down Expand Up @@ -50,8 +50,8 @@ export interface FirebaseServiceNamespace<T extends _FirebaseService> {
// eslint-disable-next-line @typescript-eslint/naming-convention
export interface _FirebaseApp extends FirebaseApp {
container: ComponentContainer;
_addComponent(component: Component): void;
_addOrOverwriteComponent(component: Component): void;
_addComponent<T extends Name>(component: Component<T>): void;
_addOrOverwriteComponent<T extends Name>(component: Component<T>): void;
_removeServiceInstance(name: string, instanceIdentifier?: string): void;
}

Expand All @@ -72,8 +72,8 @@ export interface _FirebaseNamespace extends FirebaseNamespace {
* @param allowMultipleInstances Whether the registered service supports
* multiple instances per app. If not specified, the default is false.
*/
registerComponent(
component: Component
registerComponent<T extends Name>(
component: Component<T>
): FirebaseServiceNamespace<_FirebaseService> | null;

/**
Expand Down
9 changes: 7 additions & 2 deletions packages-exp/app-exp/src/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ export const _components = new Map<string, Component<any>>();
*
* @internal
*/
export function _addComponent(app: FirebaseApp, component: Component): void {
export function _addComponent<T extends Name>(
app: FirebaseApp,
component: Component<T>
): void {
try {
(app as FirebaseAppImpl).container.addComponent(component);
} catch (e) {
Expand Down Expand Up @@ -68,7 +71,9 @@ export function _addOrOverwriteComponent(
*
* @internal
*/
export function _registerComponent(component: Component): boolean {
export function _registerComponent<T extends Name>(
component: Component<T>
): boolean {
const componentName = component.name;
if (_components.has(componentName)) {
logger.debug(
Expand Down
8 changes: 3 additions & 5 deletions packages-exp/app-exp/src/platformLoggerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
Provider,
Name
} from '@firebase/component';
import { PlatformLoggerService } from './types';
import { PlatformLoggerService, VersionService } from './types';

export class PlatformLoggerServiceImpl implements PlatformLoggerService {
constructor(private readonly container: ComponentContainer) {}
Expand All @@ -34,7 +34,7 @@ export class PlatformLoggerServiceImpl implements PlatformLoggerService {
return providers
.map(provider => {
if (isVersionServiceProvider(provider)) {
const service = provider.getImmediate();
const service = provider.getImmediate() as VersionService;
return `${service.library}/${service.version}`;
} else {
return null;
Expand All @@ -52,9 +52,7 @@ export class PlatformLoggerServiceImpl implements PlatformLoggerService {
* provides VersionService. The provider is not necessarily a 'app-version'
* provider.
*/
function isVersionServiceProvider(
provider: Provider<Name>
): provider is Provider<'app-version'> {
function isVersionServiceProvider(provider: Provider<Name>): boolean {
const component = provider.getComponent();
return component?.type === ComponentType.VERSION;
}
25 changes: 23 additions & 2 deletions packages-exp/auth-exp/src/core/auth/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
*/

import { _registerComponent, registerVersion } from '@firebase/app-exp';
import { Component, ComponentType } from '@firebase/component';
import {
Component,
ComponentType,
InstantiationMode
} from '@firebase/component';

import { version } from '../../../package.json';
import { AuthErrorCode } from '../errors';
Expand Down Expand Up @@ -86,6 +90,23 @@ export function registerAuth(clientPlatform: ClientPlatform): void {
},
ComponentType.PUBLIC
)
/**
* Auth can only be initialized by explicitly calling getAuth() or initializeAuth()
* For why we do this, See go/firebase-next-auth-init
*/
.setInstantiationMode(InstantiationMode.EXPLICIT)
/**
* Because all firebase products that depend on auth depend on auth-internal directly,
* we need to initialize auth-internal after auth is initialized to make it available to other firebase products.
*/
.setInstanceCreatedCallback(
(container, _instanceIdentifier, _instance) => {
const authInternalProvider = container.getProvider(
_ComponentName.AUTH_INTERNAL
);
authInternalProvider.initialize();
}
)
);

_registerComponent(
Expand All @@ -98,7 +119,7 @@ export function registerAuth(clientPlatform: ClientPlatform): void {
return (auth => new AuthInterop(auth))(auth);
},
ComponentType.PRIVATE
)
).setInstantiationMode(InstantiationMode.EXPLICIT)
);

registerVersion(
Expand Down
10 changes: 5 additions & 5 deletions packages/app-types/private.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import { FirebaseApp, FirebaseNamespace } from '@firebase/app-types';
import { Observer, Subscribe } from '@firebase/util';
import { FirebaseError, ErrorFactory } from '@firebase/util';
import { Component, ComponentContainer } from '@firebase/component';
import { Component, ComponentContainer, Name } from '@firebase/component';

export interface FirebaseServiceInternals {
/**
Expand Down Expand Up @@ -86,8 +86,8 @@ export interface FirebaseAppInternals {

export interface _FirebaseApp extends FirebaseApp {
container: ComponentContainer;
_addComponent(component: Component): void;
_addOrOverwriteComponent(component: Component): void;
_addComponent<T extends Name>(component: Component<T>): void;
_addOrOverwriteComponent<T extends Name>(component: Component<T>): void;
_removeServiceInstance(name: string, instanceIdentifier?: string): void;
}
export interface _FirebaseNamespace extends FirebaseNamespace {
Expand All @@ -106,8 +106,8 @@ export interface _FirebaseNamespace extends FirebaseNamespace {
* @param allowMultipleInstances Whether the registered service supports
* multiple instances per app. If not specified, the default is false.
*/
registerComponent(
component: Component
registerComponent<T extends Name>(
component: Component<T>
): FirebaseServiceNamespace<FirebaseService> | null;

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/firebaseApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export class FirebaseAppImpl implements FirebaseApp {
/**
* @param component the component being added to this app's container
*/
_addComponent(component: Component): void {
_addComponent<T extends Name>(component: Component<T>): void {
try {
this.container.addComponent(component);
} catch (e) {
Expand Down
6 changes: 2 additions & 4 deletions packages/app/src/platformLoggerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class PlatformLoggerService {
return providers
.map(provider => {
if (isVersionServiceProvider(provider)) {
const service = provider.getImmediate();
const service = (provider as Provider<'app-version'>).getImmediate();
return `${service.library}/${service.version}`;
} else {
return null;
Expand All @@ -51,9 +51,7 @@ export class PlatformLoggerService {
* provides VersionService. The provider is not necessarily a 'app-version'
* provider.
*/
function isVersionServiceProvider(
provider: Provider<Name>
): provider is Provider<'app-version'> {
function isVersionServiceProvider(provider: Provider<Name>): boolean {
const component = provider.getComponent();
return component?.type === ComponentType.VERSION;
}
10 changes: 9 additions & 1 deletion packages/component/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import {
InstanceFactory,
ComponentType,
Dictionary,
Name
Name,
onInstanceCreatedCallback
} from './types';

/**
Expand All @@ -34,6 +35,8 @@ export class Component<T extends Name = Name> {

instantiationMode = InstantiationMode.LAZY;

onInstanceCreated: onInstanceCreatedCallback<T> | null = null;

/**
*
* @param name The public service name, e.g. app, auth, firestore, database
Expand All @@ -60,4 +63,9 @@ export class Component<T extends Name = Name> {
this.serviceProps = props;
return this;
}

setInstanceCreatedCallback(callback: onInstanceCreatedCallback<T>): this {
this.onInstanceCreated = callback;
return this;
}
}
4 changes: 2 additions & 2 deletions packages/component/src/component_container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ export class ComponentContainer {
*/
getProvider<T extends Name>(name: T): Provider<T> {
if (this.providers.has(name)) {
return this.providers.get(name) as Provider<T>;
return (this.providers.get(name) as unknown) as Provider<T>;
}

// create a Provider for a service that hasn't registered with Firebase
const provider = new Provider<T>(name, this);
this.providers.set(name, provider);
this.providers.set(name, (provider as unknown) as Provider<Name>);

return provider as Provider<T>;
}
Expand Down
Loading

0 comments on commit f24d896

Please sign in to comment.