diff --git a/src/compat/auth/auth.ts b/src/compat/auth/auth.ts index 01d9c2dfe..f3338367b 100644 --- a/src/compat/auth/auth.ts +++ b/src/compat/auth/auth.ts @@ -1,5 +1,5 @@ import { isPlatformServer } from '@angular/common'; -import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core'; +import { EnvironmentInjector, Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID, inject } from '@angular/core'; import { pendingUntilEvent } from '@angular/core/rxjs-interop'; import { ɵAngularFireSchedulers } from '@angular/fire'; import { AppCheckInstances } from '@angular/fire/app-check'; @@ -55,6 +55,8 @@ export const ɵauthFactory = ( }) export class AngularFireAuth { + private readonly injector = inject(EnvironmentInjector); + /** * Observable of authentication state; as of Firebase 4.0 this is only triggered via sign-in/out */ @@ -122,7 +124,7 @@ export class AngularFireAuth { const redirectResult = auth.pipe( switchMap(auth => auth.getRedirectResult().then(it => it, () => null)), - pendingUntilEvent(), + pendingUntilEvent(this.injector), shareReplay({ bufferSize: 1, refCount: false }), ); diff --git a/src/compat/database/database.spec.ts b/src/compat/database/database.spec.ts index 48f6b20d4..09f3d0990 100644 --- a/src/compat/database/database.spec.ts +++ b/src/compat/database/database.spec.ts @@ -42,10 +42,10 @@ describe('AngularFireDatabase', () => { it('should accept a Firebase App in the constructor', (done) => { const schedulers = TestBed.runInInjectionContext(() => new ɵAngularFireSchedulers()); - const database = new AngularFireDatabase( + const database = TestBed.runInInjectionContext(() => new AngularFireDatabase( app.options, rando(), undefined, {}, zone, schedulers, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, - ); + )); expect(database instanceof AngularFireDatabase).toEqual(true); // try { database.database.app.delete().then(done, done); } catch(e) { done(); } done(); diff --git a/src/compat/database/database.ts b/src/compat/database/database.ts index 8ef116e74..1301b167a 100644 --- a/src/compat/database/database.ts +++ b/src/compat/database/database.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID, inject } from '@angular/core'; +import { EnvironmentInjector, Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID, inject } from '@angular/core'; import { ɵAngularFireSchedulers } from '@angular/fire'; import { AppCheckInstances } from '@angular/fire/app-check'; import { FIREBASE_APP_NAME, FIREBASE_OPTIONS, ɵcacheInstance, ɵfirebaseAppFactory } from '@angular/fire/compat'; @@ -31,6 +31,7 @@ export const USE_EMULATOR = new InjectionToken('angularfir }) export class AngularFireDatabase { public readonly database: firebase.database.Database; + private readonly injector = inject(EnvironmentInjector); constructor( @Inject(FIREBASE_OPTIONS) options: FirebaseOptions, @@ -73,12 +74,12 @@ export class AngularFireDatabase { if (queryFn) { query = queryFn(ref); } - return createListReference(query, this); + return createListReference(query, this, this.injector); } object(pathOrRef: PathReference): AngularFireObject { const ref = inject(NgZone).runOutsideAngular(() => getRef(this.database, pathOrRef)); - return createObjectReference(ref, this); + return createObjectReference(ref, this, this.injector); } createPushId() { diff --git a/src/compat/database/list/create-reference.ts b/src/compat/database/list/create-reference.ts index cd1addd6f..0da799454 100644 --- a/src/compat/database/list/create-reference.ts +++ b/src/compat/database/list/create-reference.ts @@ -1,4 +1,4 @@ -import { NgZone, inject } from '@angular/core'; +import { Injector, NgZone, inject } from '@angular/core'; import { pendingUntilEvent } from '@angular/core/rxjs-interop'; import type { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; @@ -10,7 +10,7 @@ import { createRemoveMethod } from './remove'; import { snapshotChanges } from './snapshot-changes'; import { stateChanges } from './state-changes'; -export function createListReference(query: DatabaseQuery, afDatabase: AngularFireDatabase): AngularFireList { +export function createListReference(query: DatabaseQuery, afDatabase: AngularFireDatabase, injector?: Injector): AngularFireList { const outsideAngularScheduler = afDatabase.schedulers.outsideAngular; const refInZone = inject(NgZone).run(() => query.ref); return { @@ -20,13 +20,13 @@ export function createListReference(query: DatabaseQuery, afDatabase: An push: (data: T) => refInZone.push(data), remove: createRemoveMethod(refInZone), snapshotChanges(events?: ChildEvent[]) { - return snapshotChanges(query, events, outsideAngularScheduler).pipe(pendingUntilEvent()); + return snapshotChanges(query, events, outsideAngularScheduler).pipe(pendingUntilEvent(injector)); }, stateChanges(events?: ChildEvent[]) { - return stateChanges(query, events, outsideAngularScheduler).pipe(pendingUntilEvent()); + return stateChanges(query, events, outsideAngularScheduler).pipe(pendingUntilEvent(injector)); }, auditTrail(events?: ChildEvent[]) { - return auditTrail(query, events, outsideAngularScheduler).pipe(pendingUntilEvent()); + return auditTrail(query, events, outsideAngularScheduler).pipe(pendingUntilEvent(injector)); }, valueChanges(events?: ChildEvent[], options?: {idField?: K}): Observable<(T & Record)[]> { const snapshotChanges$ = snapshotChanges(query, events, outsideAngularScheduler); @@ -43,7 +43,7 @@ export function createListReference(query: DatabaseQuery, afDatabase: An return a.payload.val() as T & Record } })), - pendingUntilEvent() + pendingUntilEvent(injector) ); } }; diff --git a/src/compat/database/object/create-reference.ts b/src/compat/database/object/create-reference.ts index 044d2b46d..285f0e90c 100644 --- a/src/compat/database/object/create-reference.ts +++ b/src/compat/database/object/create-reference.ts @@ -1,15 +1,16 @@ +import { Injector } from '@angular/core'; import { pendingUntilEvent } from '@angular/core/rxjs-interop'; import { map } from 'rxjs/operators'; import { AngularFireDatabase } from '../database'; import { AngularFireObject, DatabaseQuery } from '../interfaces'; import { createObjectSnapshotChanges } from './snapshot-changes'; -export function createObjectReference(query: DatabaseQuery, afDatabase: AngularFireDatabase): AngularFireObject { +export function createObjectReference(query: DatabaseQuery, afDatabase: AngularFireDatabase, injector?: Injector): AngularFireObject { return { query, snapshotChanges() { return createObjectSnapshotChanges(query, afDatabase.schedulers.outsideAngular)().pipe( - pendingUntilEvent() + pendingUntilEvent(injector) ); }, update(data: Partial) { return query.ref.update(data as any) as Promise; }, @@ -18,7 +19,7 @@ export function createObjectReference(query: DatabaseQuery, afDatabase: valueChanges() { const snapshotChanges$ = createObjectSnapshotChanges(query, afDatabase.schedulers.outsideAngular)(); return snapshotChanges$.pipe( - pendingUntilEvent(), + pendingUntilEvent(injector), map(action => action.payload.exists() ? action.payload.val() as T : null) ); }, diff --git a/src/compat/firestore/collection-group/collection-group.ts b/src/compat/firestore/collection-group/collection-group.ts index 5b0d676f3..b1a1a3441 100644 --- a/src/compat/firestore/collection-group/collection-group.ts +++ b/src/compat/firestore/collection-group/collection-group.ts @@ -1,3 +1,4 @@ +import { EnvironmentInjector, inject } from '@angular/core'; import { pendingUntilEvent } from '@angular/core/rxjs-interop'; import firebase from 'firebase/compat/app'; import { Observable, from } from 'rxjs'; @@ -27,6 +28,8 @@ import { fromCollectionRef } from '../observable/fromRef'; * fakeStock.valueChanges().subscribe(value => console.log(value)); */ export class AngularFirestoreCollectionGroup { + private readonly injector = inject(EnvironmentInjector); + /** * The constructor takes in a CollectionGroupQuery to provide wrapper methods * for data operations and data streaming. @@ -43,14 +46,14 @@ export class AngularFirestoreCollectionGroup { stateChanges(events?: DocumentChangeType[]): Observable[]> { if (!events || events.length === 0) { return docChanges(this.query, this.afs.schedulers.outsideAngular).pipe( - pendingUntilEvent() + pendingUntilEvent(this.injector) ); } return docChanges(this.query, this.afs.schedulers.outsideAngular) .pipe( map(actions => actions.filter(change => events.indexOf(change.type) > -1)), filter(changes => changes.length > 0), - pendingUntilEvent() + pendingUntilEvent(this.injector) ); } @@ -70,7 +73,7 @@ export class AngularFirestoreCollectionGroup { const validatedEvents = validateEventsArray(events); const scheduledSortedChanges$ = sortedChanges(this.query, validatedEvents, this.afs.schedulers.outsideAngular); return scheduledSortedChanges$.pipe( - pendingUntilEvent() + pendingUntilEvent(this.injector) ); } @@ -98,7 +101,7 @@ export class AngularFirestoreCollectionGroup { return a.data(); } })), - pendingUntilEvent() + pendingUntilEvent(this.injector) ); } @@ -107,7 +110,7 @@ export class AngularFirestoreCollectionGroup { */ get(options?: firebase.firestore.GetOptions) { return from(this.query.get(options)).pipe( - pendingUntilEvent() + pendingUntilEvent(this.injector) ); } diff --git a/src/compat/firestore/collection/collection.ts b/src/compat/firestore/collection/collection.ts index 7fd51378e..0a1d489b8 100644 --- a/src/compat/firestore/collection/collection.ts +++ b/src/compat/firestore/collection/collection.ts @@ -1,3 +1,4 @@ +import { EnvironmentInjector, inject } from '@angular/core'; import { pendingUntilEvent } from '@angular/core/rxjs-interop'; import firebase from 'firebase/compat/app'; import { Observable, from } from 'rxjs'; @@ -41,6 +42,8 @@ export function validateEventsArray(events?: DocumentChangeType[]) { * fakeStock.valueChanges().subscribe(value => console.log(value)); */ export class AngularFirestoreCollection { + private readonly injector = inject(EnvironmentInjector); + /** * The constructor takes in a CollectionReference and Query to provide wrapper methods * for data operations and data streaming. @@ -74,7 +77,7 @@ export class AngularFirestoreCollection { pairwise(), filter(([prior, current]: DocumentChangeTuple) => current.length > 0 || !prior), map(([, current]) => current), - pendingUntilEvent() + pendingUntilEvent(this.injector) ); } @@ -94,7 +97,7 @@ export class AngularFirestoreCollection { const validatedEvents = validateEventsArray(events); const scheduledSortedChanges$ = sortedChanges(this.query, validatedEvents, this.afs.schedulers.outsideAngular); return scheduledSortedChanges$.pipe( - pendingUntilEvent() + pendingUntilEvent(this.injector) ); } @@ -121,7 +124,7 @@ export class AngularFirestoreCollection { return a.data(); } })), - pendingUntilEvent() + pendingUntilEvent(this.injector) ); } @@ -130,7 +133,7 @@ export class AngularFirestoreCollection { */ get(options?: firebase.firestore.GetOptions) { return from(this.query.get(options)).pipe( - pendingUntilEvent(), + pendingUntilEvent(this.injector) ); } diff --git a/src/compat/firestore/document/document.ts b/src/compat/firestore/document/document.ts index 55014c727..8ffc927d3 100644 --- a/src/compat/firestore/document/document.ts +++ b/src/compat/firestore/document/document.ts @@ -1,3 +1,4 @@ +import { EnvironmentInjector, inject } from '@angular/core'; import { pendingUntilEvent } from '@angular/core/rxjs-interop'; import firebase from 'firebase/compat/app'; import { Observable, from } from 'rxjs'; @@ -30,6 +31,7 @@ import { fromDocRef } from '../observable/fromRef'; * Observable.from(fakeStock).subscribe(value => console.log(value)); */ export class AngularFirestoreDocument { + private readonly injector = inject(EnvironmentInjector); /** * The constructor takes in a DocumentReference to provide wrapper methods @@ -74,7 +76,7 @@ export class AngularFirestoreDocument { snapshotChanges(): Observable>> { const scheduledFromDocRef$ = fromDocRef(this.ref, this.afs.schedulers.outsideAngular); return scheduledFromDocRef$.pipe( - pendingUntilEvent() + pendingUntilEvent(this.injector) ); } @@ -102,7 +104,7 @@ export class AngularFirestoreDocument { */ get(options?: firebase.firestore.GetOptions) { return from(this.ref.get(options)).pipe( - pendingUntilEvent(), + pendingUntilEvent(this.injector) ); } } diff --git a/src/compat/firestore/firestore.ts b/src/compat/firestore/firestore.ts index 594726087..be3388445 100644 --- a/src/compat/firestore/firestore.ts +++ b/src/compat/firestore/firestore.ts @@ -121,6 +121,7 @@ export function associateQuery(collectionRef: CollectionReference, queryFn export class AngularFirestore { public readonly firestore: firebase.firestore.Firestore; public readonly persistenceEnabled$: Observable; + private readonly ngZone = inject(NgZone); /** * Each Feature of AngularFire has a FirebaseApp injected. This way we @@ -197,7 +198,7 @@ export class AngularFirestore { collectionRef = pathOrRef; } const { ref, query } = associateQuery(collectionRef, queryFn); - const refInZone = inject(NgZone).run(() => ref); + const refInZone = this.ngZone.run(() => ref); return new AngularFirestoreCollection(refInZone, query, this); } @@ -227,7 +228,7 @@ export class AngularFirestore { } else { ref = pathOrRef; } - const refInZone = inject(NgZone).run(() => ref); + const refInZone = this.ngZone.run(() => ref); return new AngularFirestoreDocument(refInZone, this); } diff --git a/src/compat/remote-config/remote-config.ts b/src/compat/remote-config/remote-config.ts index 4492988b4..442be66ae 100644 --- a/src/compat/remote-config/remote-config.ts +++ b/src/compat/remote-config/remote-config.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core'; +import { EnvironmentInjector, Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID, inject } from '@angular/core'; import { pendingUntilEvent } from '@angular/core/rxjs-interop'; import { ɵAngularFireSchedulers } from '@angular/fire'; import { ɵPromiseProxy, ɵapplyMixins, ɵlazySDKProxy } from '@angular/fire/compat'; @@ -121,6 +121,8 @@ export class AngularFireRemoteConfig { readonly booleans: Observable> & Record>; readonly strings: Observable> & Record>; + private readonly injector = inject(EnvironmentInjector); + constructor( @Inject(FIREBASE_OPTIONS) options: FirebaseOptions, @Optional() @Inject(FIREBASE_APP_NAME) name: string | null | undefined, @@ -186,7 +188,7 @@ export class AngularFireRemoteConfig { this.parameters = concat(default$, existing$, fresh$).pipe( scanToParametersArray(remoteConfig$), - pendingUntilEvent(), + pendingUntilEvent(this.injector), shareReplay({ bufferSize: 1, refCount: true }) ); diff --git a/src/compat/storage/ref.ts b/src/compat/storage/ref.ts index 0ce55a0e9..1d9cce47a 100644 --- a/src/compat/storage/ref.ts +++ b/src/compat/storage/ref.ts @@ -1,3 +1,4 @@ +import { Injector } from '@angular/core'; import { pendingUntilEvent } from '@angular/core/rxjs-interop'; import { observeOutsideAngular } from '@angular/fire'; import { Observable, from, of } from 'rxjs'; @@ -22,21 +23,22 @@ export interface AngularFireStorageReference { * creates observable methods from promise based methods. */ export function createStorageRef( - ref: Reference + ref: Reference, + injector?: Injector ): AngularFireStorageReference { return { getDownloadURL: () => of(undefined).pipe( observeOutsideAngular, switchMap(() => ref.getDownloadURL()), - pendingUntilEvent() + pendingUntilEvent(injector) ), getMetadata: () => of(undefined).pipe( observeOutsideAngular, switchMap(() => ref.getMetadata()), - pendingUntilEvent() + pendingUntilEvent(injector) ), delete: () => from(ref.delete()), - child: (path: string) => createStorageRef(ref.child(path)), + child: (path: string) => createStorageRef(ref.child(path), injector), updateMetadata: (meta: SettableMetadata) => from(ref.updateMetadata(meta)), put: (data: any, metadata?: UploadMetadata) => { const task = ref.put(data, metadata); diff --git a/src/compat/storage/storage.ts b/src/compat/storage/storage.ts index 6dfc7a138..57968bb9e 100644 --- a/src/compat/storage/storage.ts +++ b/src/compat/storage/storage.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core'; +import { EnvironmentInjector, Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID, inject } from '@angular/core'; import { ɵAngularFireSchedulers } from '@angular/fire'; import { AppCheckInstances } from '@angular/fire/app-check'; import { FIREBASE_APP_NAME, FIREBASE_OPTIONS, ɵcacheInstance, ɵfirebaseAppFactory } from '@angular/fire/compat'; @@ -27,6 +27,7 @@ export const USE_EMULATOR = new InjectionToken('angularfir }) export class AngularFireStorage { public readonly storage: firebase.storage.Storage; + private readonly injector = inject(EnvironmentInjector); constructor( @Inject(FIREBASE_OPTIONS) options: FirebaseOptions, @@ -59,16 +60,16 @@ export class AngularFireStorage { } ref(path: string) { - return createStorageRef(this.storage.ref(path)); + return createStorageRef(this.storage.ref(path), this.injector); } refFromURL(path: string) { - return createStorageRef(this.storage.refFromURL(path)); + return createStorageRef(this.storage.refFromURL(path), this.injector); } upload(path: string, data: any, metadata?: UploadMetadata) { const storageRef = this.storage.ref(path); - const ref = createStorageRef(storageRef); + const ref = createStorageRef(storageRef, this.injector); return ref.put(data, metadata); }