Skip to content

Commit c47bd71

Browse files
authored
Fixed onComplete for FDC (#9349)
1 parent 63167c6 commit c47bd71

File tree

13 files changed

+134
-33
lines changed

13 files changed

+134
-33
lines changed

.changeset/spotty-shirts-design.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@firebase/data-connect": patch
3+
---
4+
5+
Fixed issue where onComplete wasn't triggering when the user calls `unsubscribe` on a subscription.

common/api-review/data-connect.api.md

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,16 +109,6 @@ export interface DataConnectResult<Data, Variables> extends OpResult<Data> {
109109
ref: OperationRef<Data, Variables>;
110110
}
111111

112-
// @public
113-
export interface DataConnectSubscription<Data, Variables> {
114-
// (undocumented)
115-
errCallback?: (e?: DataConnectError) => void;
116-
// (undocumented)
117-
unsubscribe: () => void;
118-
// (undocumented)
119-
userCallback: OnResultSubscription<Data, Variables>;
120-
}
121-
122112
// @public (undocumented)
123113
export type DataSource = typeof SOURCE_CACHE | typeof SOURCE_SERVER;
124114

packages/data-connect/src/api.browser.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export function subscribe<Data, Variables>(
102102
return ref.dataConnect._queryManager.addSubscription(
103103
ref,
104104
onResult,
105+
onComplete,
105106
onError,
106107
initialCache
107108
);

packages/data-connect/src/api/DataConnect.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ export class DataConnect {
198198
// @internal
199199
enableEmulator(transportOptions: TransportOptions): void {
200200
if (
201+
this._transportOptions &&
201202
this._initialized &&
202203
!areTransportOptionsEqual(this._transportOptions, transportOptions)
203204
) {
@@ -314,7 +315,10 @@ export function validateDCOptions(dcOptions: ConnectorConfig): boolean {
314315
throw new DataConnectError(Code.INVALID_ARGUMENT, 'DC Option Required');
315316
}
316317
fields.forEach(field => {
317-
if (dcOptions[field] === null || dcOptions[field] === undefined) {
318+
if (
319+
dcOptions[field as keyof ConnectorConfig] === null ||
320+
dcOptions[field as keyof ConnectorConfig] === undefined
321+
) {
318322
throw new DataConnectError(Code.INVALID_ARGUMENT, `${field} Required`);
319323
}
320324
});

packages/data-connect/src/api/query.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,6 @@ export type OnErrorSubscription = (err?: DataConnectError) => void;
3939
* Signature for unsubscribe from `subscribe`
4040
*/
4141
export type QueryUnsubscribe = () => void;
42-
/**
43-
* Representation of user provided subscription options.
44-
*/
45-
export interface DataConnectSubscription<Data, Variables> {
46-
userCallback: OnResultSubscription<Data, Variables>;
47-
errCallback?: (e?: DataConnectError) => void;
48-
unsubscribe: () => void;
49-
}
5042

5143
/**
5244
* QueryRef object
@@ -124,7 +116,7 @@ export function queryRef<Data, Variables>(
124116
dataConnect: dcInstance,
125117
refType: QUERY_STR,
126118
name: queryName,
127-
variables
119+
variables: variables as Variables
128120
};
129121
}
130122
/**

packages/data-connect/src/core/AppCheckTokenProvider.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { Provider } from '@firebase/component';
2929
* Abstraction around AppCheck's token fetching capabilities.
3030
*/
3131
export class AppCheckTokenProvider {
32-
private appCheck?: FirebaseAppCheckInternal;
32+
private appCheck?: FirebaseAppCheckInternal | null;
3333
private serverAppAppCheckToken?: string;
3434
constructor(
3535
app: FirebaseApp,
@@ -47,13 +47,13 @@ export class AppCheckTokenProvider {
4747
}
4848
}
4949

50-
getToken(): Promise<AppCheckTokenResult> {
50+
getToken(): Promise<AppCheckTokenResult | null> {
5151
if (this.serverAppAppCheckToken) {
5252
return Promise.resolve({ token: this.serverAppAppCheckToken });
5353
}
5454

5555
if (!this.appCheck) {
56-
return new Promise<AppCheckTokenResult>((resolve, reject) => {
56+
return new Promise<AppCheckTokenResult | null>((resolve, reject) => {
5757
// Support delayed initialization of FirebaseAppCheck. This allows our
5858
// customers to initialize the RTDB SDK before initializing Firebase
5959
// AppCheck and ensures that all requests are authenticated if a token

packages/data-connect/src/core/QueryManager.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*/
1717

1818
import {
19-
DataConnectSubscription,
19+
OnCompleteSubscription,
2020
OnErrorSubscription,
2121
OnResultSubscription,
2222
QueryPromise,
@@ -39,6 +39,16 @@ import { setIfNotExists } from '../util/map';
3939

4040
import { Code, DataConnectError } from './error';
4141

42+
/**
43+
* Representation of user provided subscription options.
44+
*/
45+
interface DataConnectSubscription<Data, Variables> {
46+
userCallback: OnResultSubscription<Data, Variables>;
47+
errCallback?: (e?: DataConnectError) => void;
48+
onCompleteCallback?: () => void;
49+
unsubscribe: () => void;
50+
}
51+
4252
interface TrackedQuery<Data, Variables> {
4353
ref: Omit<OperationRef<Data, Variables>, 'dataConnect'>;
4454
subscriptions: Array<DataConnectSubscription<Data, Variables>>;
@@ -97,6 +107,7 @@ export class QueryManager {
97107
addSubscription<Data, Variables>(
98108
queryRef: OperationRef<Data, Variables>,
99109
onResultCallback: OnResultSubscription<Data, Variables>,
110+
onCompleteCallback?: OnCompleteSubscription,
100111
onErrorCallback?: OnErrorSubscription,
101112
initialCache?: OpResult<Data>
102113
): () => void {
@@ -111,13 +122,15 @@ export class QueryManager {
111122
>;
112123
const subscription = {
113124
userCallback: onResultCallback,
125+
onCompleteCallback,
114126
errCallback: onErrorCallback
115127
};
116128
const unsubscribe = (): void => {
117129
const trackedQuery = this._queries.get(key)!;
118130
trackedQuery.subscriptions = trackedQuery.subscriptions.filter(
119131
sub => sub !== subscription
120132
);
133+
onCompleteCallback?.();
121134
};
122135
if (initialCache && trackedQuery.currentCache !== initialCache) {
123136
logDebug('Initial cache found. Comparing dates.');

packages/data-connect/src/network/fetch.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ export function dcFetch<T, U>(
5656
url: string,
5757
body: DataConnectFetchBody<U>,
5858
{ signal }: AbortController,
59-
appId: string | null,
59+
appId: string | null | undefined,
6060
accessToken: string | null,
61-
appCheckToken: string | null,
61+
appCheckToken: string | null | undefined,
6262
_isUsingGen: boolean,
6363
_callerSdkType: CallerSdkType,
6464
_isUsingEmulator: boolean
@@ -135,7 +135,7 @@ interface MessageObject {
135135
message?: string;
136136
}
137137
function getMessage(obj: MessageObject): string {
138-
if ('message' in obj) {
138+
if ('message' in obj && obj.message) {
139139
return obj.message;
140140
}
141141
return JSON.stringify(obj);

packages/data-connect/src/network/transport/rest.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export class RESTTransport implements DataConnectTransport {
3434
private _project = 'p';
3535
private _serviceName: string;
3636
private _accessToken: string | null = null;
37-
private _appCheckToken: string | null = null;
37+
private _appCheckToken: string | null | undefined = null;
3838
private _lastToken: string | null = null;
3939
private _isUsingEmulator = false;
4040
constructor(
@@ -106,7 +106,7 @@ export class RESTTransport implements DataConnectTransport {
106106
this._accessToken = newToken;
107107
}
108108

109-
async getWithAuth(forceToken = false): Promise<string> {
109+
async getWithAuth(forceToken = false): Promise<string | null> {
110110
let starterPromise: Promise<string | null> = new Promise(resolve =>
111111
resolve(this._accessToken)
112112
);

packages/data-connect/src/util/validateArgs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export function validateArgs<Variables extends object>(
4646
let realVars: Variables;
4747
if (dcOrVars && 'enableEmulator' in dcOrVars) {
4848
dcInstance = dcOrVars as DataConnect;
49-
realVars = vars;
49+
realVars = vars as Variables;
5050
} else {
5151
dcInstance = getDataConnect(connectorConfig);
5252
realVars = dcOrVars as Variables;

0 commit comments

Comments
 (0)