@@ -23,24 +23,67 @@ import * as validator from '../utils/validator';
23
23
import * as utils from '../utils/index' ;
24
24
import { App } from '../app' ;
25
25
26
+ /**
27
+ * Settings to pass to the Firestore constructor.
28
+ *
29
+ * @public
30
+ */
31
+ export interface FirestoreSettings {
32
+ /**
33
+ * Use HTTP/1.1 REST transport where possible.
34
+ *
35
+ * `preferRest` will force the use of HTTP/1.1 REST transport until a method
36
+ * that requires gRPC is called. When a method requires gRPC, this Firestore
37
+ * client will load dependent gRPC libraries and then use gRPC transport for
38
+ * all communication from that point forward. Currently the only operation
39
+ * that requires gRPC is creating a snapshot listener using `onSnapshot()`.
40
+ *
41
+ * @defaultValue `undefined`
42
+ */
43
+ preferRest ?: boolean ;
44
+ }
45
+
26
46
export class FirestoreService {
27
47
28
48
private readonly appInternal : App ;
29
49
private readonly databases : Map < string , Firestore > = new Map ( ) ;
50
+ private readonly firestoreSettings : Map < string , FirestoreSettings > = new Map ( ) ;
30
51
31
52
constructor ( app : App ) {
32
53
this . appInternal = app ;
33
54
}
34
55
35
- getDatabase ( databaseId : string ) : Firestore {
56
+ getDatabase ( databaseId : string , settings ?: FirestoreSettings ) : Firestore {
57
+ settings ??= { } ;
36
58
let database = this . databases . get ( databaseId ) ;
37
59
if ( database === undefined ) {
38
- database = initFirestore ( this . app , databaseId ) ;
60
+ database = initFirestore ( this . app , databaseId , settings ) ;
39
61
this . databases . set ( databaseId , database ) ;
62
+ this . firestoreSettings . set ( databaseId , settings ) ;
63
+ } else {
64
+ if ( ! this . checkIfSameSettings ( databaseId , settings ) ) {
65
+ throw new FirebaseFirestoreError ( {
66
+ code : 'failed-precondition' ,
67
+ message : 'initializeFirestore() has already been called with ' +
68
+ 'different options. To avoid this error, call initializeFirestore() with the ' +
69
+ 'same options as when it was originally called, or call getFirestore() to return the' +
70
+ ' already initialized instance.'
71
+ } ) ;
72
+ }
40
73
}
41
74
return database ;
42
75
}
43
76
77
+ private checkIfSameSettings ( databaseId : string , firestoreSettings : FirestoreSettings ) : boolean {
78
+ // If we start passing more settings to Firestore constructor,
79
+ // replace this with deep equality check.
80
+ const existingSettings = this . firestoreSettings . get ( databaseId ) ;
81
+ if ( ! existingSettings ) {
82
+ return true ;
83
+ }
84
+ return ( existingSettings . preferRest === firestoreSettings . preferRest ) ;
85
+ }
86
+
44
87
/**
45
88
* Returns the app associated with this Storage instance.
46
89
*
@@ -51,7 +94,7 @@ export class FirestoreService {
51
94
}
52
95
}
53
96
54
- export function getFirestoreOptions ( app : App ) : Settings {
97
+ export function getFirestoreOptions ( app : App , firestoreSettings ?: FirestoreSettings ) : Settings {
55
98
if ( ! validator . isNonNullObject ( app ) || ! ( 'options' in app ) ) {
56
99
throw new FirebaseFirestoreError ( {
57
100
code : 'invalid-argument' ,
@@ -63,6 +106,7 @@ export function getFirestoreOptions(app: App): Settings {
63
106
const credential = app . options . credential ;
64
107
// eslint-disable-next-line @typescript-eslint/no-var-requires
65
108
const { version : firebaseVersion } = require ( '../../package.json' ) ;
109
+ const preferRest = firestoreSettings ?. preferRest ;
66
110
if ( credential instanceof ServiceAccountCredential ) {
67
111
return {
68
112
credentials : {
@@ -73,12 +117,15 @@ export function getFirestoreOptions(app: App): Settings {
73
117
// guaranteed to be available.
74
118
projectId : projectId ! ,
75
119
firebaseVersion,
120
+ preferRest,
76
121
} ;
77
122
} else if ( isApplicationDefault ( app . options . credential ) ) {
78
123
// Try to use the Google application default credentials.
79
124
// If an explicit project ID is not available, let Firestore client discover one from the
80
125
// environment. This prevents the users from having to set GOOGLE_CLOUD_PROJECT in GCP runtimes.
81
- return validator . isNonEmptyString ( projectId ) ? { projectId, firebaseVersion } : { firebaseVersion } ;
126
+ return validator . isNonEmptyString ( projectId )
127
+ ? { projectId, firebaseVersion, preferRest }
128
+ : { firebaseVersion, preferRest } ;
82
129
}
83
130
84
131
throw new FirebaseFirestoreError ( {
@@ -89,8 +136,8 @@ export function getFirestoreOptions(app: App): Settings {
89
136
} ) ;
90
137
}
91
138
92
- function initFirestore ( app : App , databaseId : string ) : Firestore {
93
- const options = getFirestoreOptions ( app ) ;
139
+ function initFirestore ( app : App , databaseId : string , firestoreSettings ?: FirestoreSettings ) : Firestore {
140
+ const options = getFirestoreOptions ( app , firestoreSettings ) ;
94
141
options . databaseId = databaseId ;
95
142
let firestoreDatabase : typeof Firestore ;
96
143
try {
0 commit comments