Skip to content

Commit e567618

Browse files
fix(compat): correct injectors to fix issue with compat API on v19 (#3595)
* fix: run inject in angular injection context * fix: pass injector to pendingUntilEvent pipe * TestBed for database test, inject env for Auth and RC --------- Co-authored-by: James Daniels <[email protected]>
1 parent bc926a8 commit e567618

File tree

12 files changed

+57
-39
lines changed

12 files changed

+57
-39
lines changed

Diff for: src/compat/auth/auth.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { isPlatformServer } from '@angular/common';
2-
import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core';
2+
import { EnvironmentInjector, Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID, inject } from '@angular/core';
33
import { pendingUntilEvent } from '@angular/core/rxjs-interop';
44
import { ɵAngularFireSchedulers } from '@angular/fire';
55
import { AppCheckInstances } from '@angular/fire/app-check';
@@ -55,6 +55,8 @@ export const ɵauthFactory = (
5555
})
5656
export class AngularFireAuth {
5757

58+
private readonly injector = inject(EnvironmentInjector);
59+
5860
/**
5961
* Observable of authentication state; as of Firebase 4.0 this is only triggered via sign-in/out
6062
*/
@@ -122,7 +124,7 @@ export class AngularFireAuth {
122124

123125
const redirectResult = auth.pipe(
124126
switchMap(auth => auth.getRedirectResult().then(it => it, () => null)),
125-
pendingUntilEvent(),
127+
pendingUntilEvent(this.injector),
126128
shareReplay({ bufferSize: 1, refCount: false }),
127129
);
128130

Diff for: src/compat/database/database.spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ describe('AngularFireDatabase', () => {
4242

4343
it('should accept a Firebase App in the constructor', (done) => {
4444
const schedulers = TestBed.runInInjectionContext(() => new ɵAngularFireSchedulers());
45-
const database = new AngularFireDatabase(
45+
const database = TestBed.runInInjectionContext(() => new AngularFireDatabase(
4646
app.options, rando(), undefined, {}, zone, schedulers, undefined, undefined,
4747
undefined, undefined, undefined, undefined, undefined, undefined, undefined,
48-
);
48+
));
4949
expect(database instanceof AngularFireDatabase).toEqual(true);
5050
// try { database.database.app.delete().then(done, done); } catch(e) { done(); }
5151
done();

Diff for: src/compat/database/database.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID, inject } from '@angular/core';
1+
import { EnvironmentInjector, Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID, inject } from '@angular/core';
22
import { ɵAngularFireSchedulers } from '@angular/fire';
33
import { AppCheckInstances } from '@angular/fire/app-check';
44
import { FIREBASE_APP_NAME, FIREBASE_OPTIONS, ɵcacheInstance, ɵfirebaseAppFactory } from '@angular/fire/compat';
@@ -31,6 +31,7 @@ export const USE_EMULATOR = new InjectionToken<UseEmulatorArguments>('angularfir
3131
})
3232
export class AngularFireDatabase {
3333
public readonly database: firebase.database.Database;
34+
private readonly injector = inject(EnvironmentInjector);
3435

3536
constructor(
3637
@Inject(FIREBASE_OPTIONS) options: FirebaseOptions,
@@ -73,12 +74,12 @@ export class AngularFireDatabase {
7374
if (queryFn) {
7475
query = queryFn(ref);
7576
}
76-
return createListReference<T>(query, this);
77+
return createListReference<T>(query, this, this.injector);
7778
}
7879

7980
object<T>(pathOrRef: PathReference): AngularFireObject<T> {
8081
const ref = inject(NgZone).runOutsideAngular(() => getRef(this.database, pathOrRef));
81-
return createObjectReference<T>(ref, this);
82+
return createObjectReference<T>(ref, this, this.injector);
8283
}
8384

8485
createPushId() {

Diff for: src/compat/database/list/create-reference.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NgZone, inject } from '@angular/core';
1+
import { Injector, NgZone, inject } from '@angular/core';
22
import { pendingUntilEvent } from '@angular/core/rxjs-interop';
33
import type { Observable } from 'rxjs';
44
import { map } from 'rxjs/operators';
@@ -10,7 +10,7 @@ import { createRemoveMethod } from './remove';
1010
import { snapshotChanges } from './snapshot-changes';
1111
import { stateChanges } from './state-changes';
1212

13-
export function createListReference<T= any>(query: DatabaseQuery, afDatabase: AngularFireDatabase): AngularFireList<T> {
13+
export function createListReference<T= any>(query: DatabaseQuery, afDatabase: AngularFireDatabase, injector?: Injector): AngularFireList<T> {
1414
const outsideAngularScheduler = afDatabase.schedulers.outsideAngular;
1515
const refInZone = inject(NgZone).run(() => query.ref);
1616
return {
@@ -20,13 +20,13 @@ export function createListReference<T= any>(query: DatabaseQuery, afDatabase: An
2020
push: (data: T) => refInZone.push(data),
2121
remove: createRemoveMethod(refInZone),
2222
snapshotChanges(events?: ChildEvent[]) {
23-
return snapshotChanges<T>(query, events, outsideAngularScheduler).pipe(pendingUntilEvent());
23+
return snapshotChanges<T>(query, events, outsideAngularScheduler).pipe(pendingUntilEvent(injector));
2424
},
2525
stateChanges(events?: ChildEvent[]) {
26-
return stateChanges<T>(query, events, outsideAngularScheduler).pipe(pendingUntilEvent());
26+
return stateChanges<T>(query, events, outsideAngularScheduler).pipe(pendingUntilEvent(injector));
2727
},
2828
auditTrail(events?: ChildEvent[]) {
29-
return auditTrail<T>(query, events, outsideAngularScheduler).pipe(pendingUntilEvent());
29+
return auditTrail<T>(query, events, outsideAngularScheduler).pipe(pendingUntilEvent(injector));
3030
},
3131
valueChanges<K extends string>(events?: ChildEvent[], options?: {idField?: K}): Observable<(T & Record<string, string>)[]> {
3232
const snapshotChanges$ = snapshotChanges<T>(query, events, outsideAngularScheduler);
@@ -43,7 +43,7 @@ export function createListReference<T= any>(query: DatabaseQuery, afDatabase: An
4343
return a.payload.val() as T & Record<string, string>
4444
}
4545
})),
46-
pendingUntilEvent()
46+
pendingUntilEvent(injector)
4747
);
4848
}
4949
};

Diff for: src/compat/database/object/create-reference.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1+
import { Injector } from '@angular/core';
12
import { pendingUntilEvent } from '@angular/core/rxjs-interop';
23
import { map } from 'rxjs/operators';
34
import { AngularFireDatabase } from '../database';
45
import { AngularFireObject, DatabaseQuery } from '../interfaces';
56
import { createObjectSnapshotChanges } from './snapshot-changes';
67

7-
export function createObjectReference<T= any>(query: DatabaseQuery, afDatabase: AngularFireDatabase): AngularFireObject<T> {
8+
export function createObjectReference<T= any>(query: DatabaseQuery, afDatabase: AngularFireDatabase, injector?: Injector): AngularFireObject<T> {
89
return {
910
query,
1011
snapshotChanges<T>() {
1112
return createObjectSnapshotChanges<T>(query, afDatabase.schedulers.outsideAngular)().pipe(
12-
pendingUntilEvent()
13+
pendingUntilEvent(injector)
1314
);
1415
},
1516
update(data: Partial<T>) { return query.ref.update(data as any) as Promise<void>; },
@@ -18,7 +19,7 @@ export function createObjectReference<T= any>(query: DatabaseQuery, afDatabase:
1819
valueChanges<T>() {
1920
const snapshotChanges$ = createObjectSnapshotChanges(query, afDatabase.schedulers.outsideAngular)();
2021
return snapshotChanges$.pipe(
21-
pendingUntilEvent(),
22+
pendingUntilEvent(injector),
2223
map(action => action.payload.exists() ? action.payload.val() as T : null)
2324
);
2425
},

Diff for: src/compat/firestore/collection-group/collection-group.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { EnvironmentInjector, inject } from '@angular/core';
12
import { pendingUntilEvent } from '@angular/core/rxjs-interop';
23
import firebase from 'firebase/compat/app';
34
import { Observable, from } from 'rxjs';
@@ -27,6 +28,8 @@ import { fromCollectionRef } from '../observable/fromRef';
2728
* fakeStock.valueChanges().subscribe(value => console.log(value));
2829
*/
2930
export class AngularFirestoreCollectionGroup<T = DocumentData> {
31+
private readonly injector = inject(EnvironmentInjector);
32+
3033
/**
3134
* The constructor takes in a CollectionGroupQuery to provide wrapper methods
3235
* for data operations and data streaming.
@@ -43,14 +46,14 @@ export class AngularFirestoreCollectionGroup<T = DocumentData> {
4346
stateChanges(events?: DocumentChangeType[]): Observable<DocumentChangeAction<T>[]> {
4447
if (!events || events.length === 0) {
4548
return docChanges<T>(this.query, this.afs.schedulers.outsideAngular).pipe(
46-
pendingUntilEvent()
49+
pendingUntilEvent(this.injector)
4750
);
4851
}
4952
return docChanges<T>(this.query, this.afs.schedulers.outsideAngular)
5053
.pipe(
5154
map(actions => actions.filter(change => events.indexOf(change.type) > -1)),
5255
filter(changes => changes.length > 0),
53-
pendingUntilEvent()
56+
pendingUntilEvent(this.injector)
5457
);
5558
}
5659

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

@@ -98,7 +101,7 @@ export class AngularFirestoreCollectionGroup<T = DocumentData> {
98101
return a.data();
99102
}
100103
})),
101-
pendingUntilEvent()
104+
pendingUntilEvent(this.injector)
102105
);
103106
}
104107

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

Diff for: src/compat/firestore/collection/collection.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { EnvironmentInjector, inject } from '@angular/core';
12
import { pendingUntilEvent } from '@angular/core/rxjs-interop';
23
import firebase from 'firebase/compat/app';
34
import { Observable, from } from 'rxjs';
@@ -41,6 +42,8 @@ export function validateEventsArray(events?: DocumentChangeType[]) {
4142
* fakeStock.valueChanges().subscribe(value => console.log(value));
4243
*/
4344
export class AngularFirestoreCollection<T = DocumentData> {
45+
private readonly injector = inject(EnvironmentInjector);
46+
4447
/**
4548
* The constructor takes in a CollectionReference and Query to provide wrapper methods
4649
* for data operations and data streaming.
@@ -74,7 +77,7 @@ export class AngularFirestoreCollection<T = DocumentData> {
7477
pairwise(),
7578
filter(([prior, current]: DocumentChangeTuple<T>) => current.length > 0 || !prior),
7679
map(([, current]) => current),
77-
pendingUntilEvent()
80+
pendingUntilEvent(this.injector)
7881
);
7982
}
8083

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

@@ -121,7 +124,7 @@ export class AngularFirestoreCollection<T = DocumentData> {
121124
return a.data();
122125
}
123126
})),
124-
pendingUntilEvent()
127+
pendingUntilEvent(this.injector)
125128
);
126129
}
127130

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

Diff for: src/compat/firestore/document/document.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { EnvironmentInjector, inject } from '@angular/core';
12
import { pendingUntilEvent } from '@angular/core/rxjs-interop';
23
import firebase from 'firebase/compat/app';
34
import { Observable, from } from 'rxjs';
@@ -30,6 +31,7 @@ import { fromDocRef } from '../observable/fromRef';
3031
* Observable.from(fakeStock).subscribe(value => console.log(value));
3132
*/
3233
export class AngularFirestoreDocument<T = DocumentData> {
34+
private readonly injector = inject(EnvironmentInjector);
3335

3436
/**
3537
* The constructor takes in a DocumentReference to provide wrapper methods
@@ -74,7 +76,7 @@ export class AngularFirestoreDocument<T = DocumentData> {
7476
snapshotChanges(): Observable<Action<DocumentSnapshot<T>>> {
7577
const scheduledFromDocRef$ = fromDocRef<T>(this.ref, this.afs.schedulers.outsideAngular);
7678
return scheduledFromDocRef$.pipe(
77-
pendingUntilEvent()
79+
pendingUntilEvent(this.injector)
7880
);
7981
}
8082

@@ -102,7 +104,7 @@ export class AngularFirestoreDocument<T = DocumentData> {
102104
*/
103105
get(options?: firebase.firestore.GetOptions) {
104106
return from(this.ref.get(options)).pipe(
105-
pendingUntilEvent(),
107+
pendingUntilEvent(this.injector)
106108
);
107109
}
108110
}

Diff for: src/compat/firestore/firestore.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ export function associateQuery<T>(collectionRef: CollectionReference<T>, queryFn
121121
export class AngularFirestore {
122122
public readonly firestore: firebase.firestore.Firestore;
123123
public readonly persistenceEnabled$: Observable<boolean>;
124+
private readonly ngZone = inject(NgZone);
124125

125126
/**
126127
* Each Feature of AngularFire has a FirebaseApp injected. This way we
@@ -197,7 +198,7 @@ export class AngularFirestore {
197198
collectionRef = pathOrRef;
198199
}
199200
const { ref, query } = associateQuery<T>(collectionRef, queryFn);
200-
const refInZone = inject(NgZone).run(() => ref);
201+
const refInZone = this.ngZone.run(() => ref);
201202
return new AngularFirestoreCollection<T>(refInZone, query, this);
202203
}
203204

@@ -227,7 +228,7 @@ export class AngularFirestore {
227228
} else {
228229
ref = pathOrRef;
229230
}
230-
const refInZone = inject(NgZone).run(() => ref);
231+
const refInZone = this.ngZone.run(() => ref);
231232
return new AngularFirestoreDocument<T>(refInZone, this);
232233
}
233234

Diff for: src/compat/remote-config/remote-config.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core';
1+
import { EnvironmentInjector, Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID, inject } from '@angular/core';
22
import { pendingUntilEvent } from '@angular/core/rxjs-interop';
33
import { ɵAngularFireSchedulers } from '@angular/fire';
44
import { ɵPromiseProxy, ɵapplyMixins, ɵlazySDKProxy } from '@angular/fire/compat';
@@ -121,6 +121,8 @@ export class AngularFireRemoteConfig {
121121
readonly booleans: Observable<Record<string, boolean | undefined>> & Record<string, Observable<boolean>>;
122122
readonly strings: Observable<Record<string, string | undefined>> & Record<string, Observable<string | undefined>>;
123123

124+
private readonly injector = inject(EnvironmentInjector);
125+
124126
constructor(
125127
@Inject(FIREBASE_OPTIONS) options: FirebaseOptions,
126128
@Optional() @Inject(FIREBASE_APP_NAME) name: string | null | undefined,
@@ -186,7 +188,7 @@ export class AngularFireRemoteConfig {
186188

187189
this.parameters = concat(default$, existing$, fresh$).pipe(
188190
scanToParametersArray(remoteConfig$),
189-
pendingUntilEvent(),
191+
pendingUntilEvent(this.injector),
190192
shareReplay({ bufferSize: 1, refCount: true })
191193
);
192194

Diff for: src/compat/storage/ref.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Injector } from '@angular/core';
12
import { pendingUntilEvent } from '@angular/core/rxjs-interop';
23
import { observeOutsideAngular } from '@angular/fire';
34
import { Observable, from, of } from 'rxjs';
@@ -22,21 +23,22 @@ export interface AngularFireStorageReference {
2223
* creates observable methods from promise based methods.
2324
*/
2425
export function createStorageRef(
25-
ref: Reference
26+
ref: Reference,
27+
injector?: Injector
2628
): AngularFireStorageReference {
2729
return {
2830
getDownloadURL: () => of(undefined).pipe(
2931
observeOutsideAngular,
3032
switchMap(() => ref.getDownloadURL()),
31-
pendingUntilEvent()
33+
pendingUntilEvent(injector)
3234
),
3335
getMetadata: () => of(undefined).pipe(
3436
observeOutsideAngular,
3537
switchMap(() => ref.getMetadata()),
36-
pendingUntilEvent()
38+
pendingUntilEvent(injector)
3739
),
3840
delete: () => from(ref.delete()),
39-
child: (path: string) => createStorageRef(ref.child(path)),
41+
child: (path: string) => createStorageRef(ref.child(path), injector),
4042
updateMetadata: (meta: SettableMetadata) => from(ref.updateMetadata(meta)),
4143
put: (data: any, metadata?: UploadMetadata) => {
4244
const task = ref.put(data, metadata);

Diff for: src/compat/storage/storage.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core';
1+
import { EnvironmentInjector, Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID, inject } from '@angular/core';
22
import { ɵAngularFireSchedulers } from '@angular/fire';
33
import { AppCheckInstances } from '@angular/fire/app-check';
44
import { FIREBASE_APP_NAME, FIREBASE_OPTIONS, ɵcacheInstance, ɵfirebaseAppFactory } from '@angular/fire/compat';
@@ -27,6 +27,7 @@ export const USE_EMULATOR = new InjectionToken<UseEmulatorArguments>('angularfir
2727
})
2828
export class AngularFireStorage {
2929
public readonly storage: firebase.storage.Storage;
30+
private readonly injector = inject(EnvironmentInjector);
3031

3132
constructor(
3233
@Inject(FIREBASE_OPTIONS) options: FirebaseOptions,
@@ -59,16 +60,16 @@ export class AngularFireStorage {
5960
}
6061

6162
ref(path: string) {
62-
return createStorageRef(this.storage.ref(path));
63+
return createStorageRef(this.storage.ref(path), this.injector);
6364
}
6465

6566
refFromURL(path: string) {
66-
return createStorageRef(this.storage.refFromURL(path));
67+
return createStorageRef(this.storage.refFromURL(path), this.injector);
6768
}
6869

6970
upload(path: string, data: any, metadata?: UploadMetadata) {
7071
const storageRef = this.storage.ref(path);
71-
const ref = createStorageRef(storageRef);
72+
const ref = createStorageRef(storageRef, this.injector);
7273
return ref.put(data, metadata);
7374
}
7475

0 commit comments

Comments
 (0)