diff --git a/src/analytics/analytics.module.ts b/src/analytics/analytics.module.ts index 6b81e8400..5020fa70a 100644 --- a/src/analytics/analytics.module.ts +++ b/src/analytics/analytics.module.ts @@ -1,23 +1,24 @@ import { NgModule, Optional, NgZone, InjectionToken, ModuleWithProviders, APP_INITIALIZER, Injector } from '@angular/core'; import { Analytics as FirebaseAnalytics } from 'firebase/analytics'; -import { ɵgetDefaultInstanceOf, ɵAngularFireSchedulers, VERSION, ɵisAnalyticsSupportedFactory } from '@angular/fire'; +import { ɵgetDefaultInstanceOf, ɵAngularFireSchedulers, VERSION } from '@angular/fire'; import { Analytics, ANALYTICS_PROVIDER_NAME, AnalyticsInstances } from './analytics'; import { FirebaseApps, FirebaseApp } from '@angular/fire/app'; import { registerVersion } from 'firebase/app'; import { ScreenTrackingService } from './screen-tracking.service'; import { UserTrackingService } from './user-tracking.service'; +import { isAnalyticsSupportedFactory } from './is-analytics-supported-factory'; export const PROVIDED_ANALYTICS_INSTANCES = new InjectionToken('angularfire2.analytics-instances'); export function defaultAnalyticsInstanceFactory(provided: FirebaseAnalytics[]|undefined, defaultApp: FirebaseApp) { - if (!ɵisAnalyticsSupportedFactory.sync()) { return null; } + if (!isAnalyticsSupportedFactory.sync()) { return null; } const defaultAnalytics = ɵgetDefaultInstanceOf(ANALYTICS_PROVIDER_NAME, provided, defaultApp); return defaultAnalytics && new Analytics(defaultAnalytics); } export function analyticsInstanceFactory(fn: (injector: Injector) => FirebaseAnalytics) { return (zone: NgZone, injector: Injector) => { - if (!ɵisAnalyticsSupportedFactory.sync()) { return null; } + if (!isAnalyticsSupportedFactory.sync()) { return null; } const analytics = zone.runOutsideAngular(() => fn(injector)); return new Analytics(analytics); }; @@ -45,7 +46,7 @@ const DEFAULT_ANALYTICS_INSTANCE_PROVIDER = { ANALYTICS_INSTANCES_PROVIDER, { provide: APP_INITIALIZER, - useValue: ɵisAnalyticsSupportedFactory.async, + useValue: isAnalyticsSupportedFactory.async, multi: true, } ] diff --git a/src/analytics/is-analytics-supported-factory.ts b/src/analytics/is-analytics-supported-factory.ts new file mode 100644 index 000000000..a6b63e4a9 --- /dev/null +++ b/src/analytics/is-analytics-supported-factory.ts @@ -0,0 +1,19 @@ +import { ɵisSupportedError } from '@angular/fire'; +import { isSupported } from 'firebase/analytics'; + +const isAnalyticsSupportedValueSymbol = '__angularfire_symbol__analyticsIsSupportedValue'; +const isAnalyticsSupportedPromiseSymbol = '__angularfire_symbol__analyticsIsSupported'; + +globalThis[isAnalyticsSupportedPromiseSymbol] ||= isSupported().then(it => + globalThis[isAnalyticsSupportedValueSymbol] = it +).catch(() => + globalThis[isAnalyticsSupportedValueSymbol] = false +); +export const isAnalyticsSupportedFactory = { + async: () => globalThis[isAnalyticsSupportedPromiseSymbol], + sync: () => { + const ret = globalThis[isAnalyticsSupportedValueSymbol]; + if (ret === undefined) { throw new Error(ɵisSupportedError('Analytics')); } + return ret; + } +}; diff --git a/src/analytics/overrides.ts b/src/analytics/overrides.ts index ce44ea327..08a93a137 100644 --- a/src/analytics/overrides.ts +++ b/src/analytics/overrides.ts @@ -1,3 +1,4 @@ -import { ɵisAnalyticsSupportedFactory } from '@angular/fire'; +import { isAnalyticsSupportedFactory } from './is-analytics-supported-factory'; + +export const isSupported = isAnalyticsSupportedFactory.async; -export const isSupported = ɵisAnalyticsSupportedFactory.async; diff --git a/src/core.ts b/src/core.ts index d939be9fe..0bd19b78c 100644 --- a/src/core.ts +++ b/src/core.ts @@ -1,69 +1,14 @@ import { Version } from '@angular/core'; import { FirebaseApp, getApps } from 'firebase/app'; import { ComponentContainer } from '@firebase/component'; -import { isSupported as isRemoteConfigSupported } from 'firebase/remote-config'; -import { isSupported as isMessagingSupported } from 'firebase/messaging'; -import { isSupported as isAnalyticsSupported } from 'firebase/analytics'; export const VERSION = new Version('ANGULARFIRE2_VERSION'); -const isAnalyticsSupportedValueSymbol = '__angularfire_symbol__analyticsIsSupportedValue'; -const isAnalyticsSupportedPromiseSymbol = '__angularfire_symbol__analyticsIsSupported'; -const isRemoteConfigSupportedValueSymbol = '__angularfire_symbol__remoteConfigIsSupportedValue'; -const isRemoteConfigSupportedPromiseSymbol = '__angularfire_symbol__remoteConfigIsSupported'; -const isMessagingSupportedValueSymbol = '__angularfire_symbol__messagingIsSupportedValue'; -const isMessagingSupportedPromiseSymbol = '__angularfire_symbol__messagingIsSupported'; - -globalThis[isAnalyticsSupportedPromiseSymbol] ||= isAnalyticsSupported().then(it => - globalThis[isAnalyticsSupportedValueSymbol] = it -).catch(() => - globalThis[isAnalyticsSupportedValueSymbol] = false -); - -globalThis[isMessagingSupportedPromiseSymbol] ||= isMessagingSupported().then(it => - globalThis[isMessagingSupportedValueSymbol] = it -).catch(() => - globalThis[isMessagingSupportedValueSymbol] = false -); - -globalThis[isRemoteConfigSupportedPromiseSymbol] ||= isRemoteConfigSupported().then(it => - globalThis[isRemoteConfigSupportedValueSymbol] = it -).catch(() => - globalThis[isRemoteConfigSupportedValueSymbol] = false -); - -const isSupportedError = (module: string) => +export const ɵisSupportedError = (module: string) => `The APP_INITIALIZER that is "making" isSupported() sync for the sake of convenient DI has not resolved in this context. Rather than injecting ${module} in the constructor, first ensure that ${module} is supported by calling \`await isSupported()\`, then retrieve the instance from the injector manually \`injector.get(${module})\`.`; -export const ɵisMessagingSupportedFactory = { - async: () => globalThis[isMessagingSupportedPromiseSymbol], - sync: () => { - const ret = globalThis[isMessagingSupportedValueSymbol]; - if (ret === undefined) { throw new Error(isSupportedError('Messaging')); } - return ret; - } -}; - -export const ɵisRemoteConfigSupportedFactory = { - async: () => globalThis[isRemoteConfigSupportedPromiseSymbol], - sync: () => { - const ret = globalThis[isRemoteConfigSupportedValueSymbol]; - if (ret === undefined) { throw new Error(isSupportedError('RemoteConfig')); } - return ret; - } -}; - -export const ɵisAnalyticsSupportedFactory = { - async: () => globalThis[isAnalyticsSupportedPromiseSymbol], - sync: () => { - const ret = globalThis[isAnalyticsSupportedValueSymbol]; - if (ret === undefined) { throw new Error(isSupportedError('Analytics')); } - return ret; - } -}; - // TODO is there a better way to get at the internal types? interface FirebaseAppWithContainer extends FirebaseApp { container: ComponentContainer; diff --git a/src/messaging/is-messaging-supported-factory.ts b/src/messaging/is-messaging-supported-factory.ts new file mode 100644 index 000000000..57e5b0f0f --- /dev/null +++ b/src/messaging/is-messaging-supported-factory.ts @@ -0,0 +1,20 @@ +import { ɵisSupportedError } from '@angular/fire'; +import { isSupported } from 'firebase/messaging'; + +const isMessagingSupportedPromiseSymbol = '__angularfire_symbol__messagingIsSupported'; +const isMessagingSupportedValueSymbol = '__angularfire_symbol__messagingIsSupportedValue'; + +globalThis[isMessagingSupportedPromiseSymbol] ||= isSupported().then(it => + globalThis[isMessagingSupportedValueSymbol] = it +).catch(() => + globalThis[isMessagingSupportedValueSymbol] = false +); + +export const isMessagingSupportedFactory = { + async: () => globalThis[isMessagingSupportedPromiseSymbol], + sync: () => { + const ret = globalThis[isMessagingSupportedValueSymbol]; + if (ret === undefined) { throw new Error(ɵisSupportedError('Messaging')); } + return ret; + } +}; diff --git a/src/messaging/messaging.module.ts b/src/messaging/messaging.module.ts index 09275d8b3..efb863c03 100644 --- a/src/messaging/messaging.module.ts +++ b/src/messaging/messaging.module.ts @@ -1,21 +1,22 @@ import { NgModule, Optional, NgZone, InjectionToken, ModuleWithProviders, Injector, APP_INITIALIZER } from '@angular/core'; import { Messaging as FirebaseMessaging } from 'firebase/messaging'; -import { ɵgetDefaultInstanceOf, ɵAngularFireSchedulers, VERSION, ɵisMessagingSupportedFactory } from '@angular/fire'; +import { ɵgetDefaultInstanceOf, ɵAngularFireSchedulers, VERSION } from '@angular/fire'; import { Messaging, MessagingInstances, MESSAGING_PROVIDER_NAME } from './messaging'; import { FirebaseApps, FirebaseApp } from '@angular/fire/app'; import { registerVersion } from 'firebase/app'; +import { isMessagingSupportedFactory } from './is-messaging-supported-factory'; const PROVIDED_MESSAGING_INSTANCES = new InjectionToken('angularfire2.messaging-instances'); export function defaultMessagingInstanceFactory(provided: FirebaseMessaging[]|undefined, defaultApp: FirebaseApp) { - if (!ɵisMessagingSupportedFactory.sync()) { return null; } + if (!isMessagingSupportedFactory.sync()) { return null; } const defaultMessaging = ɵgetDefaultInstanceOf(MESSAGING_PROVIDER_NAME, provided, defaultApp); return defaultMessaging && new Messaging(defaultMessaging); } export function messagingInstanceFactory(fn: (injector: Injector) => FirebaseMessaging) { return (zone: NgZone, injector: Injector) => { - if (!ɵisMessagingSupportedFactory.sync()) { return null; } + if (!isMessagingSupportedFactory.sync()) { return null; } const messaging = zone.runOutsideAngular(() => fn(injector)); return new Messaging(messaging); }; @@ -43,7 +44,7 @@ const DEFAULT_MESSAGING_INSTANCE_PROVIDER = { MESSAGING_INSTANCES_PROVIDER, { provide: APP_INITIALIZER, - useValue: ɵisMessagingSupportedFactory.async, + useValue: isMessagingSupportedFactory.async, multi: true, }, ] diff --git a/src/messaging/overrides.ts b/src/messaging/overrides.ts index 88c61df14..79a81fc23 100644 --- a/src/messaging/overrides.ts +++ b/src/messaging/overrides.ts @@ -1,3 +1,3 @@ -import { ɵisMessagingSupportedFactory } from '@angular/fire'; +import { isMessagingSupportedFactory } from './is-messaging-supported-factory'; -export const isSupported = ɵisMessagingSupportedFactory.async; +export const isSupported = isMessagingSupportedFactory.async; diff --git a/src/remote-config/is-remote-config-supported-factory.ts b/src/remote-config/is-remote-config-supported-factory.ts new file mode 100644 index 000000000..8838150ca --- /dev/null +++ b/src/remote-config/is-remote-config-supported-factory.ts @@ -0,0 +1,20 @@ +import { isSupported } from 'firebase/remote-config'; +import { ɵisSupportedError } from '@angular/fire'; + +const isRemoteConfigSupportedValueSymbol = '__angularfire_symbol__remoteConfigIsSupportedValue'; +const isRemoteConfigSupportedPromiseSymbol = '__angularfire_symbol__remoteConfigIsSupported'; + +globalThis[isRemoteConfigSupportedPromiseSymbol] ||= isSupported().then(it => + globalThis[isRemoteConfigSupportedValueSymbol] = it +).catch(() => + globalThis[isRemoteConfigSupportedValueSymbol] = false +); + +export const isRemoteConfigSupportedFactory = { + async: () => globalThis[isRemoteConfigSupportedPromiseSymbol], + sync: () => { + const ret = globalThis[isRemoteConfigSupportedValueSymbol]; + if (ret === undefined) { throw new Error(ɵisSupportedError('RemoteConfig')); } + return ret; + } +}; diff --git a/src/remote-config/overrides.ts b/src/remote-config/overrides.ts index 6478d5a11..d5e0b6e16 100644 --- a/src/remote-config/overrides.ts +++ b/src/remote-config/overrides.ts @@ -1,3 +1,3 @@ -import { ɵisRemoteConfigSupportedFactory } from '@angular/fire'; +import { isRemoteConfigSupportedFactory } from './is-remote-config-supported-factory'; -export const isSupported = ɵisRemoteConfigSupportedFactory.async; +export const isSupported = isRemoteConfigSupportedFactory.async; diff --git a/src/remote-config/remote-config.module.ts b/src/remote-config/remote-config.module.ts index 4a26bd2e1..5bd985d0c 100644 --- a/src/remote-config/remote-config.module.ts +++ b/src/remote-config/remote-config.module.ts @@ -1,9 +1,10 @@ import { NgModule, Optional, NgZone, InjectionToken, ModuleWithProviders, Injector, APP_INITIALIZER } from '@angular/core'; import { RemoteConfig as FirebaseRemoteConfig } from 'firebase/remote-config'; -import { ɵgetDefaultInstanceOf, ɵAngularFireSchedulers, VERSION, ɵisRemoteConfigSupportedFactory } from '@angular/fire'; +import { ɵgetDefaultInstanceOf, ɵAngularFireSchedulers, VERSION } from '@angular/fire'; import { RemoteConfig, RemoteConfigInstances, REMOTE_CONFIG_PROVIDER_NAME } from './remote-config'; import { FirebaseApps, FirebaseApp } from '@angular/fire/app'; import { registerVersion } from 'firebase/app'; +import { isRemoteConfigSupportedFactory } from './is-remote-config-supported-factory'; export const PROVIDED_REMOTE_CONFIG_INSTANCES = new InjectionToken('angularfire2.remote-config-instances'); @@ -11,14 +12,14 @@ export function defaultRemoteConfigInstanceFactory( provided: FirebaseRemoteConfig[]|undefined, defaultApp: FirebaseApp, ) { - if (!ɵisRemoteConfigSupportedFactory.sync()) { return null; } + if (!isRemoteConfigSupportedFactory.sync()) { return null; } const defaultRemoteConfig = ɵgetDefaultInstanceOf(REMOTE_CONFIG_PROVIDER_NAME, provided, defaultApp); return defaultRemoteConfig && new RemoteConfig(defaultRemoteConfig); } export function remoteConfigInstanceFactory(fn: (injector: Injector) => FirebaseRemoteConfig) { return (zone: NgZone, injector: Injector) => { - if (!ɵisRemoteConfigSupportedFactory.sync()) { return null; } + if (!isRemoteConfigSupportedFactory.sync()) { return null; } const remoteConfig = zone.runOutsideAngular(() => fn(injector)); return new RemoteConfig(remoteConfig); }; @@ -46,7 +47,7 @@ const DEFAULT_REMOTE_CONFIG_INSTANCE_PROVIDER = { REMOTE_CONFIG_INSTANCES_PROVIDER, { provide: APP_INITIALIZER, - useValue: ɵisRemoteConfigSupportedFactory.async, + useValue: isRemoteConfigSupportedFactory.async, multi: true, }, ]