Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(compat): correct injectors to fix issue with compat API on v19 #3595

Merged
merged 3 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/compat/auth/auth.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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 }),
);

Expand Down
4 changes: 2 additions & 2 deletions src/compat/database/database.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
7 changes: 4 additions & 3 deletions src/compat/database/database.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -31,6 +31,7 @@ export const USE_EMULATOR = new InjectionToken<UseEmulatorArguments>('angularfir
})
export class AngularFireDatabase {
public readonly database: firebase.database.Database;
private readonly injector = inject(EnvironmentInjector);

constructor(
@Inject(FIREBASE_OPTIONS) options: FirebaseOptions,
Expand Down Expand Up @@ -73,12 +74,12 @@ export class AngularFireDatabase {
if (queryFn) {
query = queryFn(ref);
}
return createListReference<T>(query, this);
return createListReference<T>(query, this, this.injector);
}

object<T>(pathOrRef: PathReference): AngularFireObject<T> {
const ref = inject(NgZone).runOutsideAngular(() => getRef(this.database, pathOrRef));
return createObjectReference<T>(ref, this);
return createObjectReference<T>(ref, this, this.injector);
}

createPushId() {
Expand Down
12 changes: 6 additions & 6 deletions src/compat/database/list/create-reference.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -10,7 +10,7 @@ import { createRemoveMethod } from './remove';
import { snapshotChanges } from './snapshot-changes';
import { stateChanges } from './state-changes';

export function createListReference<T= any>(query: DatabaseQuery, afDatabase: AngularFireDatabase): AngularFireList<T> {
export function createListReference<T= any>(query: DatabaseQuery, afDatabase: AngularFireDatabase, injector?: Injector): AngularFireList<T> {
const outsideAngularScheduler = afDatabase.schedulers.outsideAngular;
const refInZone = inject(NgZone).run(() => query.ref);
return {
Expand All @@ -20,13 +20,13 @@ export function createListReference<T= any>(query: DatabaseQuery, afDatabase: An
push: (data: T) => refInZone.push(data),
remove: createRemoveMethod(refInZone),
snapshotChanges(events?: ChildEvent[]) {
return snapshotChanges<T>(query, events, outsideAngularScheduler).pipe(pendingUntilEvent());
return snapshotChanges<T>(query, events, outsideAngularScheduler).pipe(pendingUntilEvent(injector));
},
stateChanges(events?: ChildEvent[]) {
return stateChanges<T>(query, events, outsideAngularScheduler).pipe(pendingUntilEvent());
return stateChanges<T>(query, events, outsideAngularScheduler).pipe(pendingUntilEvent(injector));
},
auditTrail(events?: ChildEvent[]) {
return auditTrail<T>(query, events, outsideAngularScheduler).pipe(pendingUntilEvent());
return auditTrail<T>(query, events, outsideAngularScheduler).pipe(pendingUntilEvent(injector));
},
valueChanges<K extends string>(events?: ChildEvent[], options?: {idField?: K}): Observable<(T & Record<string, string>)[]> {
const snapshotChanges$ = snapshotChanges<T>(query, events, outsideAngularScheduler);
Expand All @@ -43,7 +43,7 @@ export function createListReference<T= any>(query: DatabaseQuery, afDatabase: An
return a.payload.val() as T & Record<string, string>
}
})),
pendingUntilEvent()
pendingUntilEvent(injector)
);
}
};
Expand Down
7 changes: 4 additions & 3 deletions src/compat/database/object/create-reference.ts
Original file line number Diff line number Diff line change
@@ -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<T= any>(query: DatabaseQuery, afDatabase: AngularFireDatabase): AngularFireObject<T> {
export function createObjectReference<T= any>(query: DatabaseQuery, afDatabase: AngularFireDatabase, injector?: Injector): AngularFireObject<T> {
return {
query,
snapshotChanges<T>() {
return createObjectSnapshotChanges<T>(query, afDatabase.schedulers.outsideAngular)().pipe(
pendingUntilEvent()
pendingUntilEvent(injector)
);
},
update(data: Partial<T>) { return query.ref.update(data as any) as Promise<void>; },
Expand All @@ -18,7 +19,7 @@ export function createObjectReference<T= any>(query: DatabaseQuery, afDatabase:
valueChanges<T>() {
const snapshotChanges$ = createObjectSnapshotChanges(query, afDatabase.schedulers.outsideAngular)();
return snapshotChanges$.pipe(
pendingUntilEvent(),
pendingUntilEvent(injector),
map(action => action.payload.exists() ? action.payload.val() as T : null)
);
},
Expand Down
13 changes: 8 additions & 5 deletions src/compat/firestore/collection-group/collection-group.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -27,6 +28,8 @@ import { fromCollectionRef } from '../observable/fromRef';
* fakeStock.valueChanges().subscribe(value => console.log(value));
*/
export class AngularFirestoreCollectionGroup<T = DocumentData> {
private readonly injector = inject(EnvironmentInjector);

/**
* The constructor takes in a CollectionGroupQuery to provide wrapper methods
* for data operations and data streaming.
Expand All @@ -43,14 +46,14 @@ export class AngularFirestoreCollectionGroup<T = DocumentData> {
stateChanges(events?: DocumentChangeType[]): Observable<DocumentChangeAction<T>[]> {
if (!events || events.length === 0) {
return docChanges<T>(this.query, this.afs.schedulers.outsideAngular).pipe(
pendingUntilEvent()
pendingUntilEvent(this.injector)
);
}
return docChanges<T>(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)
);
}

Expand All @@ -70,7 +73,7 @@ export class AngularFirestoreCollectionGroup<T = DocumentData> {
const validatedEvents = validateEventsArray(events);
const scheduledSortedChanges$ = sortedChanges<T>(this.query, validatedEvents, this.afs.schedulers.outsideAngular);
return scheduledSortedChanges$.pipe(
pendingUntilEvent()
pendingUntilEvent(this.injector)
);
}

Expand Down Expand Up @@ -98,7 +101,7 @@ export class AngularFirestoreCollectionGroup<T = DocumentData> {
return a.data();
}
})),
pendingUntilEvent()
pendingUntilEvent(this.injector)
);
}

Expand All @@ -107,7 +110,7 @@ export class AngularFirestoreCollectionGroup<T = DocumentData> {
*/
get(options?: firebase.firestore.GetOptions) {
return from(this.query.get(options)).pipe(
pendingUntilEvent()
pendingUntilEvent(this.injector)
);
}

Expand Down
11 changes: 7 additions & 4 deletions src/compat/firestore/collection/collection.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -41,6 +42,8 @@ export function validateEventsArray(events?: DocumentChangeType[]) {
* fakeStock.valueChanges().subscribe(value => console.log(value));
*/
export class AngularFirestoreCollection<T = DocumentData> {
private readonly injector = inject(EnvironmentInjector);

/**
* The constructor takes in a CollectionReference and Query to provide wrapper methods
* for data operations and data streaming.
Expand Down Expand Up @@ -74,7 +77,7 @@ export class AngularFirestoreCollection<T = DocumentData> {
pairwise(),
filter(([prior, current]: DocumentChangeTuple<T>) => current.length > 0 || !prior),
map(([, current]) => current),
pendingUntilEvent()
pendingUntilEvent(this.injector)
);
}

Expand All @@ -94,7 +97,7 @@ export class AngularFirestoreCollection<T = DocumentData> {
const validatedEvents = validateEventsArray(events);
const scheduledSortedChanges$ = sortedChanges<T>(this.query, validatedEvents, this.afs.schedulers.outsideAngular);
return scheduledSortedChanges$.pipe(
pendingUntilEvent()
pendingUntilEvent(this.injector)
);
}

Expand All @@ -121,7 +124,7 @@ export class AngularFirestoreCollection<T = DocumentData> {
return a.data();
}
})),
pendingUntilEvent()
pendingUntilEvent(this.injector)
);
}

Expand All @@ -130,7 +133,7 @@ export class AngularFirestoreCollection<T = DocumentData> {
*/
get(options?: firebase.firestore.GetOptions) {
return from(this.query.get(options)).pipe(
pendingUntilEvent(),
pendingUntilEvent(this.injector)
);
}

Expand Down
6 changes: 4 additions & 2 deletions src/compat/firestore/document/document.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -30,6 +31,7 @@ import { fromDocRef } from '../observable/fromRef';
* Observable.from(fakeStock).subscribe(value => console.log(value));
*/
export class AngularFirestoreDocument<T = DocumentData> {
private readonly injector = inject(EnvironmentInjector);

/**
* The constructor takes in a DocumentReference to provide wrapper methods
Expand Down Expand Up @@ -74,7 +76,7 @@ export class AngularFirestoreDocument<T = DocumentData> {
snapshotChanges(): Observable<Action<DocumentSnapshot<T>>> {
const scheduledFromDocRef$ = fromDocRef<T>(this.ref, this.afs.schedulers.outsideAngular);
return scheduledFromDocRef$.pipe(
pendingUntilEvent()
pendingUntilEvent(this.injector)
);
}

Expand Down Expand Up @@ -102,7 +104,7 @@ export class AngularFirestoreDocument<T = DocumentData> {
*/
get(options?: firebase.firestore.GetOptions) {
return from(this.ref.get(options)).pipe(
pendingUntilEvent(),
pendingUntilEvent(this.injector)
);
}
}
5 changes: 3 additions & 2 deletions src/compat/firestore/firestore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ export function associateQuery<T>(collectionRef: CollectionReference<T>, queryFn
export class AngularFirestore {
public readonly firestore: firebase.firestore.Firestore;
public readonly persistenceEnabled$: Observable<boolean>;
private readonly ngZone = inject(NgZone);

/**
* Each Feature of AngularFire has a FirebaseApp injected. This way we
Expand Down Expand Up @@ -197,7 +198,7 @@ export class AngularFirestore {
collectionRef = pathOrRef;
}
const { ref, query } = associateQuery<T>(collectionRef, queryFn);
const refInZone = inject(NgZone).run(() => ref);
const refInZone = this.ngZone.run(() => ref);
return new AngularFirestoreCollection<T>(refInZone, query, this);
}

Expand Down Expand Up @@ -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<T>(refInZone, this);
}

Expand Down
6 changes: 4 additions & 2 deletions src/compat/remote-config/remote-config.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -121,6 +121,8 @@ export class AngularFireRemoteConfig {
readonly booleans: Observable<Record<string, boolean | undefined>> & Record<string, Observable<boolean>>;
readonly strings: Observable<Record<string, string | undefined>> & Record<string, Observable<string | undefined>>;

private readonly injector = inject(EnvironmentInjector);

constructor(
@Inject(FIREBASE_OPTIONS) options: FirebaseOptions,
@Optional() @Inject(FIREBASE_APP_NAME) name: string | null | undefined,
Expand Down Expand Up @@ -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 })
);

Expand Down
10 changes: 6 additions & 4 deletions src/compat/storage/ref.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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);
Expand Down
9 changes: 5 additions & 4 deletions src/compat/storage/storage.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -27,6 +27,7 @@ export const USE_EMULATOR = new InjectionToken<UseEmulatorArguments>('angularfir
})
export class AngularFireStorage {
public readonly storage: firebase.storage.Storage;
private readonly injector = inject(EnvironmentInjector);

constructor(
@Inject(FIREBASE_OPTIONS) options: FirebaseOptions,
Expand Down Expand Up @@ -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);
}

Expand Down
Loading