firebase-admin 12.2.0 → 12.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/lib/app/core.d.ts +1 -1
  2. package/lib/app/core.js +1 -1
  3. package/lib/app/credential-factory.d.ts +1 -1
  4. package/lib/app/credential-factory.js +1 -1
  5. package/lib/app/credential-internal.d.ts +1 -1
  6. package/lib/app/credential-internal.js +4 -4
  7. package/lib/app/credential.d.ts +1 -1
  8. package/lib/app/credential.js +1 -1
  9. package/lib/app/firebase-app.d.ts +1 -1
  10. package/lib/app/firebase-app.js +1 -1
  11. package/lib/app/firebase-namespace.d.ts +1 -1
  12. package/lib/app/firebase-namespace.js +1 -1
  13. package/lib/app/index.d.ts +1 -1
  14. package/lib/app/index.js +1 -1
  15. package/lib/app/lifecycle.d.ts +1 -1
  16. package/lib/app/lifecycle.js +1 -1
  17. package/lib/app-check/app-check-api-client-internal.d.ts +1 -1
  18. package/lib/app-check/app-check-api-client-internal.js +1 -1
  19. package/lib/app-check/app-check-api.d.ts +1 -1
  20. package/lib/app-check/app-check-api.js +1 -1
  21. package/lib/app-check/app-check-namespace.d.ts +1 -1
  22. package/lib/app-check/app-check-namespace.js +1 -1
  23. package/lib/app-check/app-check.d.ts +1 -1
  24. package/lib/app-check/app-check.js +1 -1
  25. package/lib/app-check/index.d.ts +1 -1
  26. package/lib/app-check/index.js +1 -1
  27. package/lib/app-check/token-generator.d.ts +1 -1
  28. package/lib/app-check/token-generator.js +1 -1
  29. package/lib/app-check/token-verifier.d.ts +1 -1
  30. package/lib/app-check/token-verifier.js +1 -1
  31. package/lib/auth/action-code-settings-builder.d.ts +1 -1
  32. package/lib/auth/action-code-settings-builder.js +1 -1
  33. package/lib/auth/auth-api-request.d.ts +1 -1
  34. package/lib/auth/auth-api-request.js +2 -2
  35. package/lib/auth/auth-config.d.ts +1 -1
  36. package/lib/auth/auth-config.js +1 -1
  37. package/lib/auth/auth-namespace.d.ts +1 -1
  38. package/lib/auth/auth-namespace.js +1 -1
  39. package/lib/auth/auth.d.ts +1 -1
  40. package/lib/auth/auth.js +1 -1
  41. package/lib/auth/base-auth.d.ts +1 -1
  42. package/lib/auth/base-auth.js +1 -1
  43. package/lib/auth/identifier.d.ts +1 -1
  44. package/lib/auth/identifier.js +1 -1
  45. package/lib/auth/index.d.ts +1 -1
  46. package/lib/auth/index.js +1 -1
  47. package/lib/auth/project-config-manager.d.ts +1 -1
  48. package/lib/auth/project-config-manager.js +1 -1
  49. package/lib/auth/project-config.d.ts +1 -1
  50. package/lib/auth/project-config.js +1 -1
  51. package/lib/auth/tenant-manager.d.ts +1 -1
  52. package/lib/auth/tenant-manager.js +1 -1
  53. package/lib/auth/tenant.d.ts +1 -1
  54. package/lib/auth/tenant.js +1 -1
  55. package/lib/auth/token-generator.d.ts +1 -1
  56. package/lib/auth/token-generator.js +1 -1
  57. package/lib/auth/token-verifier.d.ts +1 -1
  58. package/lib/auth/token-verifier.js +1 -1
  59. package/lib/auth/user-import-builder.d.ts +1 -1
  60. package/lib/auth/user-import-builder.js +1 -1
  61. package/lib/auth/user-record.d.ts +1 -1
  62. package/lib/auth/user-record.js +1 -1
  63. package/lib/credential/index.d.ts +1 -1
  64. package/lib/credential/index.js +1 -1
  65. package/lib/database/database-namespace.d.ts +1 -1
  66. package/lib/database/database-namespace.js +1 -1
  67. package/lib/database/database.d.ts +1 -1
  68. package/lib/database/database.js +2 -2
  69. package/lib/database/index.d.ts +1 -1
  70. package/lib/database/index.js +1 -1
  71. package/lib/default-namespace.d.ts +1 -1
  72. package/lib/default-namespace.js +1 -1
  73. package/lib/eventarc/cloudevent.d.ts +1 -1
  74. package/lib/eventarc/cloudevent.js +1 -1
  75. package/lib/eventarc/eventarc-client-internal.d.ts +1 -1
  76. package/lib/eventarc/eventarc-client-internal.js +1 -1
  77. package/lib/eventarc/eventarc-utils.d.ts +1 -1
  78. package/lib/eventarc/eventarc-utils.js +1 -1
  79. package/lib/eventarc/eventarc.d.ts +1 -1
  80. package/lib/eventarc/eventarc.js +1 -1
  81. package/lib/eventarc/index.d.ts +1 -1
  82. package/lib/eventarc/index.js +1 -1
  83. package/lib/extensions/extensions-api-client-internal.d.ts +1 -1
  84. package/lib/extensions/extensions-api-client-internal.js +1 -1
  85. package/lib/extensions/extensions-api.d.ts +1 -1
  86. package/lib/extensions/extensions-api.js +1 -1
  87. package/lib/extensions/extensions.d.ts +1 -1
  88. package/lib/extensions/extensions.js +1 -1
  89. package/lib/extensions/index.d.ts +1 -1
  90. package/lib/extensions/index.js +1 -1
  91. package/lib/firebase-namespace-api.d.ts +1 -1
  92. package/lib/firebase-namespace-api.js +1 -1
  93. package/lib/firestore/firestore-internal.d.ts +1 -1
  94. package/lib/firestore/firestore-internal.js +1 -1
  95. package/lib/firestore/firestore-namespace.d.ts +1 -1
  96. package/lib/firestore/firestore-namespace.js +1 -1
  97. package/lib/firestore/index.d.ts +1 -1
  98. package/lib/firestore/index.js +1 -1
  99. package/lib/functions/functions-api-client-internal.d.ts +1 -1
  100. package/lib/functions/functions-api-client-internal.js +3 -3
  101. package/lib/functions/functions-api.d.ts +1 -1
  102. package/lib/functions/functions-api.js +1 -1
  103. package/lib/functions/functions.d.ts +1 -1
  104. package/lib/functions/functions.js +1 -1
  105. package/lib/functions/index.d.ts +1 -1
  106. package/lib/functions/index.js +1 -1
  107. package/lib/index.d.ts +1 -1
  108. package/lib/index.js +1 -1
  109. package/lib/installations/index.d.ts +1 -1
  110. package/lib/installations/index.js +1 -1
  111. package/lib/installations/installations-namespace.d.ts +1 -1
  112. package/lib/installations/installations-namespace.js +1 -1
  113. package/lib/installations/installations-request-handler.d.ts +1 -1
  114. package/lib/installations/installations-request-handler.js +2 -2
  115. package/lib/installations/installations.d.ts +1 -1
  116. package/lib/installations/installations.js +1 -1
  117. package/lib/instance-id/index.d.ts +1 -1
  118. package/lib/instance-id/index.js +1 -1
  119. package/lib/instance-id/instance-id-namespace.d.ts +1 -1
  120. package/lib/instance-id/instance-id-namespace.js +1 -1
  121. package/lib/instance-id/instance-id.d.ts +1 -1
  122. package/lib/instance-id/instance-id.js +1 -1
  123. package/lib/machine-learning/index.d.ts +1 -1
  124. package/lib/machine-learning/index.js +1 -1
  125. package/lib/machine-learning/machine-learning-api-client.d.ts +1 -1
  126. package/lib/machine-learning/machine-learning-api-client.js +1 -1
  127. package/lib/machine-learning/machine-learning-namespace.d.ts +1 -1
  128. package/lib/machine-learning/machine-learning-namespace.js +1 -1
  129. package/lib/machine-learning/machine-learning-utils.d.ts +1 -1
  130. package/lib/machine-learning/machine-learning-utils.js +1 -1
  131. package/lib/machine-learning/machine-learning.d.ts +1 -1
  132. package/lib/machine-learning/machine-learning.js +1 -1
  133. package/lib/messaging/batch-request-internal.d.ts +4 -4
  134. package/lib/messaging/batch-request-internal.js +2 -2
  135. package/lib/messaging/index.d.ts +1 -1
  136. package/lib/messaging/index.js +1 -1
  137. package/lib/messaging/messaging-api-request-internal.d.ts +15 -4
  138. package/lib/messaging/messaging-api-request-internal.js +39 -10
  139. package/lib/messaging/messaging-api.d.ts +1 -1
  140. package/lib/messaging/messaging-api.js +1 -1
  141. package/lib/messaging/messaging-errors-internal.d.ts +6 -6
  142. package/lib/messaging/messaging-errors-internal.js +4 -4
  143. package/lib/messaging/messaging-internal.d.ts +1 -1
  144. package/lib/messaging/messaging-internal.js +1 -1
  145. package/lib/messaging/messaging-namespace.d.ts +1 -1
  146. package/lib/messaging/messaging-namespace.js +1 -1
  147. package/lib/messaging/messaging.d.ts +16 -1
  148. package/lib/messaging/messaging.js +37 -9
  149. package/lib/project-management/android-app.d.ts +1 -1
  150. package/lib/project-management/android-app.js +1 -1
  151. package/lib/project-management/app-metadata.d.ts +1 -1
  152. package/lib/project-management/app-metadata.js +1 -1
  153. package/lib/project-management/index.d.ts +1 -1
  154. package/lib/project-management/index.js +1 -1
  155. package/lib/project-management/ios-app.d.ts +1 -1
  156. package/lib/project-management/ios-app.js +1 -1
  157. package/lib/project-management/project-management-api-request-internal.d.ts +1 -1
  158. package/lib/project-management/project-management-api-request-internal.js +3 -3
  159. package/lib/project-management/project-management-namespace.d.ts +1 -1
  160. package/lib/project-management/project-management-namespace.js +1 -1
  161. package/lib/project-management/project-management.d.ts +1 -1
  162. package/lib/project-management/project-management.js +1 -1
  163. package/lib/remote-config/condition-evaluator-internal.d.ts +1 -1
  164. package/lib/remote-config/condition-evaluator-internal.js +20 -14
  165. package/lib/remote-config/index.d.ts +1 -1
  166. package/lib/remote-config/index.js +1 -1
  167. package/lib/remote-config/internal/value-impl.d.ts +1 -1
  168. package/lib/remote-config/internal/value-impl.js +1 -1
  169. package/lib/remote-config/remote-config-api-client-internal.d.ts +1 -1
  170. package/lib/remote-config/remote-config-api-client-internal.js +1 -1
  171. package/lib/remote-config/remote-config-api.d.ts +1 -1
  172. package/lib/remote-config/remote-config-api.js +1 -1
  173. package/lib/remote-config/remote-config-namespace.d.ts +1 -1
  174. package/lib/remote-config/remote-config-namespace.js +1 -1
  175. package/lib/remote-config/remote-config.d.ts +1 -1
  176. package/lib/remote-config/remote-config.js +1 -1
  177. package/lib/security-rules/index.d.ts +1 -1
  178. package/lib/security-rules/index.js +1 -1
  179. package/lib/security-rules/security-rules-api-client-internal.d.ts +1 -1
  180. package/lib/security-rules/security-rules-api-client-internal.js +1 -1
  181. package/lib/security-rules/security-rules-internal.d.ts +1 -1
  182. package/lib/security-rules/security-rules-internal.js +1 -1
  183. package/lib/security-rules/security-rules-namespace.d.ts +1 -1
  184. package/lib/security-rules/security-rules-namespace.js +1 -1
  185. package/lib/security-rules/security-rules.d.ts +1 -1
  186. package/lib/security-rules/security-rules.js +1 -1
  187. package/lib/storage/index.d.ts +1 -1
  188. package/lib/storage/index.js +1 -1
  189. package/lib/storage/storage-namespace.d.ts +1 -1
  190. package/lib/storage/storage-namespace.js +1 -1
  191. package/lib/storage/storage.d.ts +1 -1
  192. package/lib/storage/storage.js +1 -1
  193. package/lib/storage/utils.d.ts +1 -1
  194. package/lib/storage/utils.js +1 -1
  195. package/lib/utils/api-request.d.ts +134 -42
  196. package/lib/utils/api-request.js +430 -186
  197. package/lib/utils/crypto-signer.d.ts +1 -1
  198. package/lib/utils/crypto-signer.js +2 -2
  199. package/lib/utils/deep-copy.d.ts +1 -1
  200. package/lib/utils/deep-copy.js +1 -1
  201. package/lib/utils/error.d.ts +1 -1
  202. package/lib/utils/error.js +1 -1
  203. package/lib/utils/index.d.ts +1 -1
  204. package/lib/utils/index.js +1 -1
  205. package/lib/utils/jwt.d.ts +1 -1
  206. package/lib/utils/jwt.js +3 -3
  207. package/lib/utils/validator.d.ts +1 -1
  208. package/lib/utils/validator.js +1 -1
  209. package/package.json +4 -5
@@ -1,4 +1,4 @@
1
- /*! firebase-admin v12.2.0 */
1
+ /*! firebase-admin v12.3.0 */
2
2
  "use strict";
3
3
  /*!
4
4
  * @license
@@ -17,16 +17,17 @@
17
17
  * limitations under the License.
18
18
  */
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.ExponentialBackoffPoller = exports.ApiSettings = exports.AuthorizedHttpClient = exports.parseHttpResponse = exports.HttpClient = exports.defaultRetryConfig = exports.HttpError = void 0;
20
+ exports.Http2SessionHandler = exports.ExponentialBackoffPoller = exports.ApiSettings = exports.AuthorizedHttp2Client = exports.AuthorizedHttpClient = exports.parseHttpResponse = exports.Http2Client = exports.HttpClient = exports.RequestClient = exports.defaultRetryConfig = exports.RequestResponseError = void 0;
21
21
  const error_1 = require("./error");
22
22
  const validator = require("./validator");
23
23
  const http = require("http");
24
24
  const https = require("https");
25
+ const http2 = require("http2");
25
26
  const url = require("url");
26
27
  const events_1 = require("events");
27
- class DefaultHttpResponse {
28
+ class DefaultRequestResponse {
28
29
  /**
29
- * Constructs a new HttpResponse from the given LowLevelResponse.
30
+ * Constructs a new `RequestResponse` from the given `LowLevelResponse`.
30
31
  */
31
32
  constructor(resp) {
32
33
  this.status = resp.status;
@@ -57,10 +58,10 @@ class DefaultHttpResponse {
57
58
  }
58
59
  }
59
60
  /**
60
- * Represents a multipart HTTP response. Parts that constitute the response body can be accessed
61
+ * Represents a multipart HTTP or HTTP/2 response. Parts that constitute the response body can be accessed
61
62
  * via the multipart getter. Getters for text and data throw errors.
62
63
  */
63
- class MultipartHttpResponse {
64
+ class MultipartRequestResponse {
64
65
  constructor(resp) {
65
66
  this.status = resp.status;
66
67
  this.headers = resp.headers;
@@ -76,19 +77,19 @@ class MultipartHttpResponse {
76
77
  return false;
77
78
  }
78
79
  }
79
- class HttpError extends Error {
80
+ class RequestResponseError extends Error {
80
81
  constructor(response) {
81
82
  super(`Server responded with status ${response.status}.`);
82
83
  this.response = response;
83
84
  // Set the prototype so that instanceof checks will work correctly.
84
85
  // See: https://github.com/Microsoft/TypeScript/issues/13965
85
- Object.setPrototypeOf(this, HttpError.prototype);
86
+ Object.setPrototypeOf(this, RequestResponseError.prototype);
86
87
  }
87
88
  }
88
- exports.HttpError = HttpError;
89
+ exports.RequestResponseError = RequestResponseError;
89
90
  /**
90
- * Default retry configuration for HTTP requests. Retries up to 4 times on connection reset and timeout errors
91
- * as well as HTTP 503 errors. Exposed as a function to ensure that every HttpClient gets its own RetryConfig
91
+ * Default retry configuration for HTTP and HTTP/2 requests. Retries up to 4 times on connection reset and timeout
92
+ * errors as well as 503 errors. Exposed as a function to ensure that every `RequestClient` gets its own `RetryConfig`
92
93
  * instance.
93
94
  */
94
95
  function defaultRetryConfig() {
@@ -102,7 +103,7 @@ function defaultRetryConfig() {
102
103
  }
103
104
  exports.defaultRetryConfig = defaultRetryConfig;
104
105
  /**
105
- * Ensures that the given RetryConfig object is valid.
106
+ * Ensures that the given `RetryConfig` object is valid.
106
107
  *
107
108
  * @param retry - The configuration to be validated.
108
109
  */
@@ -125,64 +126,18 @@ function validateRetryConfig(retry) {
125
126
  throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_ARGUMENT, 'ioErrorCodes must be an array');
126
127
  }
127
128
  }
128
- class HttpClient {
129
+ class RequestClient {
129
130
  constructor(retry = defaultRetryConfig()) {
130
- this.retry = retry;
131
- if (this.retry) {
131
+ if (retry) {
132
+ this.retry = retry;
132
133
  validateRetryConfig(this.retry);
133
134
  }
134
135
  }
135
- /**
136
- * Sends an HTTP request to a remote server. If the server responds with a successful response (2xx), the returned
137
- * promise resolves with an HttpResponse. If the server responds with an error (3xx, 4xx, 5xx), the promise rejects
138
- * with an HttpError. In case of all other errors, the promise rejects with a FirebaseAppError. If a request fails
139
- * due to a low-level network error, transparently retries the request once before rejecting the promise.
140
- *
141
- * If the request data is specified as an object, it will be serialized into a JSON string. The application/json
142
- * content-type header will also be automatically set in this case. For all other payload types, the content-type
143
- * header should be explicitly set by the caller. To send a JSON leaf value (e.g. "foo", 5), parse it into JSON,
144
- * and pass as a string or a Buffer along with the appropriate content-type header.
145
- *
146
- * @param config - HTTP request to be sent.
147
- * @returns A promise that resolves with the response details.
148
- */
149
- send(config) {
150
- return this.sendWithRetry(config);
151
- }
152
- /**
153
- * Sends an HTTP request. In the event of an error, retries the HTTP request according to the
154
- * RetryConfig set on the HttpClient.
155
- *
156
- * @param config - HTTP request to be sent.
157
- * @param retryAttempts - Number of retries performed up to now.
158
- * @returns A promise that resolves with the response details.
159
- */
160
- sendWithRetry(config, retryAttempts = 0) {
161
- return AsyncHttpCall.invoke(config)
162
- .then((resp) => {
163
- return this.createHttpResponse(resp);
164
- })
165
- .catch((err) => {
166
- const [delayMillis, canRetry] = this.getRetryDelayMillis(retryAttempts, err);
167
- if (canRetry && this.retry && delayMillis <= this.retry.maxDelayInMillis) {
168
- return this.waitForRetry(delayMillis).then(() => {
169
- return this.sendWithRetry(config, retryAttempts + 1);
170
- });
171
- }
172
- if (err.response) {
173
- throw new HttpError(this.createHttpResponse(err.response));
174
- }
175
- if (err.code === 'ETIMEDOUT') {
176
- throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_TIMEOUT, `Error while making request: ${err.message}.`);
177
- }
178
- throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_ERROR, `Error while making request: ${err.message}. Error code: ${err.code}`);
179
- });
180
- }
181
- createHttpResponse(resp) {
136
+ createRequestResponse(resp) {
182
137
  if (resp.multipart) {
183
- return new MultipartHttpResponse(resp);
138
+ return new MultipartRequestResponse(resp);
184
139
  }
185
- return new DefaultHttpResponse(resp);
140
+ return new DefaultRequestResponse(resp);
186
141
  }
187
142
  waitForRetry(delayMillis) {
188
143
  if (delayMillis > 0) {
@@ -231,8 +186,8 @@ class HttpClient {
231
186
  }
232
187
  return false;
233
188
  }
234
- /**
235
- * Parses the Retry-After HTTP header as a milliseconds value. Return value is negative if the Retry-After header
189
+ /**???
190
+ * Parses the Retry-After header as a milliseconds value. Return value is negative if the Retry-After header
236
191
  * contains an expired timestamp or otherwise malformed.
237
192
  */
238
193
  parseRetryAfterIntoMillis(retryAfter) {
@@ -258,13 +213,119 @@ class HttpClient {
258
213
  return Math.min(delayInSeconds * 1000, this.retry.maxDelayInMillis);
259
214
  }
260
215
  }
216
+ exports.RequestClient = RequestClient;
217
+ class HttpClient extends RequestClient {
218
+ constructor(retry) {
219
+ super(retry);
220
+ }
221
+ /**
222
+ * Sends an HTTP request to a remote server. If the server responds with a successful response (2xx), the returned
223
+ * promise resolves with an `RequestResponse`. If the server responds with an error (3xx, 4xx, 5xx), the promise
224
+ * rejects with an `RequestResponseError`. In case of all other errors, the promise rejects with a `FirebaseAppError`.
225
+ * If a request fails due to a low-level network error, the client transparently retries the request once before
226
+ * rejecting the promise.
227
+ *
228
+ * If the request data is specified as an object, it will be serialized into a JSON string. The application/json
229
+ * content-type header will also be automatically set in this case. For all other payload types, the content-type
230
+ * header should be explicitly set by the caller. To send a JSON leaf value (e.g. "foo", 5), parse it into JSON,
231
+ * and pass as a string or a Buffer along with the appropriate content-type header.
232
+ *
233
+ * @param config - HTTP request to be sent.
234
+ * @returns A promise that resolves with the response details.
235
+ */
236
+ send(config) {
237
+ return this.sendWithRetry(config);
238
+ }
239
+ /**
240
+ * Sends an HTTP request. In the event of an error, retries the HTTP request according to the
241
+ * `RetryConfig` set on the `HttpClient`.
242
+ *
243
+ * @param config - HTTP request to be sent.
244
+ * @param retryAttempts - Number of retries performed up to now.
245
+ * @returns A promise that resolves with the response details.
246
+ */
247
+ sendWithRetry(config, retryAttempts = 0) {
248
+ return AsyncHttpCall.invoke(config)
249
+ .then((resp) => {
250
+ return this.createRequestResponse(resp);
251
+ })
252
+ .catch((err) => {
253
+ const [delayMillis, canRetry] = this.getRetryDelayMillis(retryAttempts, err);
254
+ if (canRetry && this.retry && delayMillis <= this.retry.maxDelayInMillis) {
255
+ return this.waitForRetry(delayMillis).then(() => {
256
+ return this.sendWithRetry(config, retryAttempts + 1);
257
+ });
258
+ }
259
+ if (err.response) {
260
+ throw new RequestResponseError(this.createRequestResponse(err.response));
261
+ }
262
+ if (err.code === 'ETIMEDOUT') {
263
+ throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_TIMEOUT, `Error while making request: ${err.message}.`);
264
+ }
265
+ throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_ERROR, `Error while making request: ${err.message}. Error code: ${err.code}`);
266
+ });
267
+ }
268
+ }
261
269
  exports.HttpClient = HttpClient;
270
+ class Http2Client extends RequestClient {
271
+ constructor(retry = defaultRetryConfig()) {
272
+ super(retry);
273
+ }
274
+ /**
275
+ * Sends an HTTP/2 request to a remote server. If the server responds with a successful response (2xx), the returned
276
+ * promise resolves with an `RequestResponse`. If the server responds with an error (3xx, 4xx, 5xx), the promise
277
+ * rejects with an `RequestResponseError`. In case of all other errors, the promise rejects with a `FirebaseAppError`.
278
+ * If a request fails due to a low-level network error, the client transparently retries the request once before
279
+ * rejecting the promise.
280
+ *
281
+ * If the request data is specified as an object, it will be serialized into a JSON string. The application/json
282
+ * content-type header will also be automatically set in this case. For all other payload types, the content-type
283
+ * header should be explicitly set by the caller. To send a JSON leaf value (e.g. "foo", 5), parse it into JSON,
284
+ * and pass as a string or a Buffer along with the appropriate content-type header.
285
+ *
286
+ * @param config - HTTP/2 request to be sent.
287
+ * @returns A promise that resolves with the response details.
288
+ */
289
+ send(config) {
290
+ return this.sendWithRetry(config);
291
+ }
292
+ /**
293
+ * Sends an HTTP/2 request. In the event of an error, retries the HTTP/2 request according to the
294
+ * `RetryConfig` set on the `Http2Client`.
295
+ *
296
+ * @param config - HTTP/2 request to be sent.
297
+ * @param retryAttempts - Number of retries performed up to now.
298
+ * @returns A promise that resolves with the response details.
299
+ */
300
+ sendWithRetry(config, retryAttempts = 0) {
301
+ return AsyncHttp2Call.invoke(config)
302
+ .then((resp) => {
303
+ return this.createRequestResponse(resp);
304
+ })
305
+ .catch((err) => {
306
+ const [delayMillis, canRetry] = this.getRetryDelayMillis(retryAttempts, err);
307
+ if (canRetry && this.retry && delayMillis <= this.retry.maxDelayInMillis) {
308
+ return this.waitForRetry(delayMillis).then(() => {
309
+ return this.sendWithRetry(config, retryAttempts + 1);
310
+ });
311
+ }
312
+ if (err.response) {
313
+ throw new RequestResponseError(this.createRequestResponse(err.response));
314
+ }
315
+ if (err.code === 'ETIMEDOUT') {
316
+ throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_TIMEOUT, `Error while making request: ${err.message}.`);
317
+ }
318
+ throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_ERROR, `Error while making request: ${err.message}. Error code: ${err.code}`);
319
+ });
320
+ }
321
+ }
322
+ exports.Http2Client = Http2Client;
262
323
  /**
263
- * Parses a full HTTP response message containing both a header and a body.
324
+ * Parses a full HTTP or HTTP/2 response message containing both a header and a body.
264
325
  *
265
- * @param response - The HTTP response to be parsed.
266
- * @param config - The request configuration that resulted in the HTTP response.
267
- * @returns An object containing the parsed HTTP status, headers and the body.
326
+ * @param response - The HTTP or HTTP/2 response to be parsed.
327
+ * @param config - The request configuration that resulted in the HTTP or HTTP/2 response.
328
+ * @returns An object containing the response's parsed status, headers and the body.
268
329
  */
269
330
  function parseHttpResponse(response, config) {
270
331
  const responseText = validator.isBuffer(response) ?
@@ -297,82 +358,16 @@ function parseHttpResponse(response, config) {
297
358
  if (!validator.isNumber(lowLevelResponse.status)) {
298
359
  throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INTERNAL_ERROR, 'Malformed HTTP status line.');
299
360
  }
300
- return new DefaultHttpResponse(lowLevelResponse);
361
+ return new DefaultRequestResponse(lowLevelResponse);
301
362
  }
302
363
  exports.parseHttpResponse = parseHttpResponse;
303
364
  /**
304
- * A helper class for sending HTTP requests over the wire. This is a wrapper around the standard
305
- * http and https packages of Node.js, providing content processing, timeouts and error handling.
365
+ * A helper class for common functionality needed to send requests over the wire.
306
366
  * It also wraps the callback API of the Node.js standard library in a more flexible Promise API.
307
367
  */
308
- class AsyncHttpCall {
309
- /**
310
- * Sends an HTTP request based on the provided configuration.
311
- */
312
- static invoke(config) {
313
- return new AsyncHttpCall(config).promise;
314
- }
315
- constructor(config) {
316
- try {
317
- this.config = new HttpRequestConfigImpl(config);
318
- this.options = this.config.buildRequestOptions();
319
- this.entity = this.config.buildEntity(this.options.headers);
320
- this.promise = new Promise((resolve, reject) => {
321
- this.resolve = resolve;
322
- this.reject = reject;
323
- this.execute();
324
- });
325
- }
326
- catch (err) {
327
- this.promise = Promise.reject(this.enhanceError(err, null));
328
- }
329
- }
330
- execute() {
331
- const transport = this.options.protocol === 'https:' ? https : http;
332
- const req = transport.request(this.options, (res) => {
333
- this.handleResponse(res, req);
334
- });
335
- // Handle errors
336
- req.on('error', (err) => {
337
- if (req.aborted) {
338
- return;
339
- }
340
- this.enhanceAndReject(err, null, req);
341
- });
342
- const timeout = this.config.timeout;
343
- const timeoutCallback = () => {
344
- req.abort();
345
- this.rejectWithError(`timeout of ${timeout}ms exceeded`, 'ETIMEDOUT', req);
346
- };
347
- if (timeout) {
348
- // Listen to timeouts and throw an error.
349
- req.setTimeout(timeout, timeoutCallback);
350
- }
351
- // Send the request
352
- req.end(this.entity);
353
- }
354
- handleResponse(res, req) {
355
- if (req.aborted) {
356
- return;
357
- }
358
- if (!res.statusCode) {
359
- throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INTERNAL_ERROR, 'Expected a statusCode on the response from a ClientRequest');
360
- }
361
- const response = {
362
- status: res.statusCode,
363
- headers: res.headers,
364
- request: req,
365
- data: undefined,
366
- config: this.config,
367
- };
368
- const boundary = this.getMultipartBoundary(res.headers);
369
- const respStream = this.uncompressResponse(res);
370
- if (boundary) {
371
- this.handleMultipartResponse(response, respStream, boundary);
372
- }
373
- else {
374
- this.handleRegularResponse(response, respStream);
375
- }
368
+ class AsyncRequestCall {
369
+ constructor(configImpl) {
370
+ this.configImpl = configImpl;
376
371
  }
377
372
  /**
378
373
  * Extracts multipart boundary from the HTTP header. The content-type header of a multipart
@@ -401,19 +396,6 @@ class AsyncHttpCall {
401
396
  }, emptyObject);
402
397
  return headerParams.boundary;
403
398
  }
404
- uncompressResponse(res) {
405
- // Uncompress the response body transparently if required.
406
- let respStream = res;
407
- const encodings = ['gzip', 'compress', 'deflate'];
408
- if (res.headers['content-encoding'] && encodings.indexOf(res.headers['content-encoding']) !== -1) {
409
- // Add the unzipper to the body stream processing pipeline.
410
- const zlib = require('zlib'); // eslint-disable-line @typescript-eslint/no-var-requires
411
- respStream = respStream.pipe(zlib.createUnzip());
412
- // Remove the content-encoding in order to not confuse downstream operations.
413
- delete res.headers['content-encoding'];
414
- }
415
- return respStream;
416
- }
417
399
  handleMultipartResponse(response, respStream, boundary) {
418
400
  const busboy = require('@fastify/busboy'); // eslint-disable-line @typescript-eslint/no-var-requires
419
401
  const multipartParser = new busboy.Dicer({ boundary });
@@ -441,7 +423,7 @@ class AsyncHttpCall {
441
423
  });
442
424
  respStream.on('error', (err) => {
443
425
  const req = response.request;
444
- if (req && req.aborted) {
426
+ if (req && req.destroyed) {
445
427
  return;
446
428
  }
447
429
  this.enhanceAndReject(err, null, req);
@@ -452,7 +434,7 @@ class AsyncHttpCall {
452
434
  });
453
435
  }
454
436
  /**
455
- * Finalizes the current HTTP call in-flight by either resolving or rejecting the associated
437
+ * Finalizes the current request call in-flight by either resolving or rejecting the associated
456
438
  * promise. In the event of an error, adds additional useful information to the returned error.
457
439
  */
458
440
  finalizeResponse(response) {
@@ -465,7 +447,7 @@ class AsyncHttpCall {
465
447
  }
466
448
  /**
467
449
  * Creates a new error from the given message, and enhances it with other information available.
468
- * Then the promise associated with this HTTP call is rejected with the resulting error.
450
+ * Then the promise associated with this request call is rejected with the resulting error.
469
451
  */
470
452
  rejectWithError(message, code, request, response) {
471
453
  const error = new Error(message);
@@ -475,11 +457,11 @@ class AsyncHttpCall {
475
457
  this.reject(this.enhanceError(error, code, request, response));
476
458
  }
477
459
  /**
478
- * Enhances the given error by adding more information to it. Specifically, the HttpRequestConfig,
460
+ * Enhances the given error by adding more information to it. Specifically, the request config,
479
461
  * the underlying request and response will be attached to the error.
480
462
  */
481
463
  enhanceError(error, code, request, response) {
482
- error.config = this.config;
464
+ error.config = this.configImpl;
483
465
  if (code) {
484
466
  error.code = code;
485
467
  }
@@ -489,10 +471,190 @@ class AsyncHttpCall {
489
471
  }
490
472
  }
491
473
  /**
492
- * An adapter class for extracting options and entity data from an HttpRequestConfig.
474
+ * A helper class for sending HTTP requests over the wire. This is a wrapper around the standard
475
+ * http and https packages of Node.js, providing content processing, timeouts and error handling.
476
+ * It also wraps the callback API of the Node.js standard library in a more flexible Promise API.
493
477
  */
494
- class HttpRequestConfigImpl {
478
+ class AsyncHttpCall extends AsyncRequestCall {
479
+ /**
480
+ * Sends an HTTP request based on the provided configuration.
481
+ */
482
+ static invoke(config) {
483
+ return new AsyncHttpCall(config).promise;
484
+ }
495
485
  constructor(config) {
486
+ const httpConfigImpl = new HttpRequestConfigImpl(config);
487
+ super(httpConfigImpl);
488
+ try {
489
+ this.httpConfigImpl = httpConfigImpl;
490
+ this.options = this.httpConfigImpl.buildRequestOptions();
491
+ this.entity = this.httpConfigImpl.buildEntity(this.options.headers);
492
+ this.promise = new Promise((resolve, reject) => {
493
+ this.resolve = resolve;
494
+ this.reject = reject;
495
+ this.execute();
496
+ });
497
+ }
498
+ catch (err) {
499
+ this.promise = Promise.reject(this.enhanceError(err, null));
500
+ }
501
+ }
502
+ execute() {
503
+ const transport = this.options.protocol === 'https:' ? https : http;
504
+ const req = transport.request(this.options, (res) => {
505
+ this.handleResponse(res, req);
506
+ });
507
+ // Handle errors
508
+ req.on('error', (err) => {
509
+ if (req.aborted) {
510
+ return;
511
+ }
512
+ this.enhanceAndReject(err, null, req);
513
+ });
514
+ const timeout = this.httpConfigImpl.timeout;
515
+ const timeoutCallback = () => {
516
+ req.destroy();
517
+ this.rejectWithError(`timeout of ${timeout}ms exceeded`, 'ETIMEDOUT', req);
518
+ };
519
+ if (timeout) {
520
+ // Listen to timeouts and throw an error.
521
+ req.setTimeout(timeout, timeoutCallback);
522
+ }
523
+ // Send the request
524
+ req.end(this.entity);
525
+ }
526
+ handleResponse(res, req) {
527
+ if (req.aborted) {
528
+ return;
529
+ }
530
+ if (!res.statusCode) {
531
+ throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INTERNAL_ERROR, 'Expected a statusCode on the response from a ClientRequest');
532
+ }
533
+ const response = {
534
+ status: res.statusCode,
535
+ headers: res.headers,
536
+ request: req,
537
+ data: undefined,
538
+ config: this.httpConfigImpl,
539
+ };
540
+ const boundary = this.getMultipartBoundary(res.headers);
541
+ const respStream = this.uncompressResponse(res);
542
+ if (boundary) {
543
+ this.handleMultipartResponse(response, respStream, boundary);
544
+ }
545
+ else {
546
+ this.handleRegularResponse(response, respStream);
547
+ }
548
+ }
549
+ uncompressResponse(res) {
550
+ // Uncompress the response body transparently if required.
551
+ let respStream = res;
552
+ const encodings = ['gzip', 'compress', 'deflate'];
553
+ if (res.headers['content-encoding'] && encodings.indexOf(res.headers['content-encoding']) !== -1) {
554
+ // Add the unzipper to the body stream processing pipeline.
555
+ const zlib = require('zlib'); // eslint-disable-line @typescript-eslint/no-var-requires
556
+ respStream = respStream.pipe(zlib.createUnzip());
557
+ // Remove the content-encoding in order to not confuse downstream operations.
558
+ delete res.headers['content-encoding'];
559
+ }
560
+ return respStream;
561
+ }
562
+ }
563
+ class AsyncHttp2Call extends AsyncRequestCall {
564
+ /**
565
+ * Sends an HTTP2 request based on the provided configuration.
566
+ */
567
+ static invoke(config) {
568
+ return new AsyncHttp2Call(config).promise;
569
+ }
570
+ constructor(config) {
571
+ const http2ConfigImpl = new Http2RequestConfigImpl(config);
572
+ super(http2ConfigImpl);
573
+ try {
574
+ this.http2ConfigImpl = http2ConfigImpl;
575
+ this.options = this.http2ConfigImpl.buildRequestOptions();
576
+ this.entity = this.http2ConfigImpl.buildEntity(this.options.headers);
577
+ this.promise = new Promise((resolve, reject) => {
578
+ this.resolve = resolve;
579
+ this.reject = reject;
580
+ this.execute();
581
+ });
582
+ }
583
+ catch (err) {
584
+ this.promise = Promise.reject(this.enhanceError(err, null));
585
+ }
586
+ }
587
+ execute() {
588
+ const req = this.http2ConfigImpl.http2SessionHandler.session.request({
589
+ ':method': this.options.method,
590
+ ':scheme': this.options.protocol,
591
+ ':path': this.options.path,
592
+ ...this.options.headers
593
+ });
594
+ req.on('response', (headers) => {
595
+ this.handleHttp2Response(headers, req);
596
+ });
597
+ // Handle errors
598
+ req.on('error', (err) => {
599
+ if (req.aborted) {
600
+ return;
601
+ }
602
+ this.enhanceAndReject(err, null, req);
603
+ });
604
+ const timeout = this.http2ConfigImpl.timeout;
605
+ const timeoutCallback = () => {
606
+ req.destroy();
607
+ this.rejectWithError(`timeout of ${timeout}ms exceeded`, 'ETIMEDOUT', req);
608
+ };
609
+ if (timeout) {
610
+ // Listen to timeouts and throw an error.
611
+ req.setTimeout(timeout, timeoutCallback);
612
+ }
613
+ req.end(this.entity);
614
+ }
615
+ handleHttp2Response(headers, stream) {
616
+ if (stream.aborted) {
617
+ return;
618
+ }
619
+ if (!headers[':status']) {
620
+ throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INTERNAL_ERROR, 'Expected a statusCode on the response from a ClientRequest');
621
+ }
622
+ const response = {
623
+ status: headers[':status'],
624
+ headers: headers,
625
+ request: stream,
626
+ data: undefined,
627
+ config: this.http2ConfigImpl,
628
+ };
629
+ const boundary = this.getMultipartBoundary(headers);
630
+ const respStream = this.uncompressResponse(headers, stream);
631
+ if (boundary) {
632
+ this.handleMultipartResponse(response, respStream, boundary);
633
+ }
634
+ else {
635
+ this.handleRegularResponse(response, respStream);
636
+ }
637
+ }
638
+ uncompressResponse(headers, stream) {
639
+ // Uncompress the response body transparently if required.
640
+ let respStream = stream;
641
+ const encodings = ['gzip', 'compress', 'deflate'];
642
+ if (headers['content-encoding'] && encodings.indexOf(headers['content-encoding']) !== -1) {
643
+ // Add the unzipper to the body stream processing pipeline.
644
+ const zlib = require('zlib'); // eslint-disable-line @typescript-eslint/no-var-requires
645
+ respStream = respStream.pipe(zlib.createUnzip());
646
+ // Remove the content-encoding in order to not confuse downstream operations.
647
+ delete headers['content-encoding'];
648
+ }
649
+ return respStream;
650
+ }
651
+ }
652
+ /**
653
+ * An adapter class with common functionality needed to extract options and entity data from a `RequestConfig`.
654
+ */
655
+ class BaseRequestConfigImpl {
656
+ constructor(config) {
657
+ this.config = config;
496
658
  this.config = config;
497
659
  }
498
660
  get method() {
@@ -510,27 +672,6 @@ class HttpRequestConfigImpl {
510
672
  get timeout() {
511
673
  return this.config.timeout;
512
674
  }
513
- get httpAgent() {
514
- return this.config.httpAgent;
515
- }
516
- buildRequestOptions() {
517
- const parsed = this.buildUrl();
518
- const protocol = parsed.protocol;
519
- let port = parsed.port;
520
- if (!port) {
521
- const isHttps = protocol === 'https:';
522
- port = isHttps ? '443' : '80';
523
- }
524
- return {
525
- protocol,
526
- hostname: parsed.hostname,
527
- port,
528
- path: parsed.path,
529
- method: this.method,
530
- agent: this.httpAgent,
531
- headers: Object.assign({}, this.headers),
532
- };
533
- }
534
675
  buildEntity(headers) {
535
676
  let data;
536
677
  if (!this.hasEntity() || !this.isEntityEnclosingRequest()) {
@@ -588,6 +729,58 @@ class HttpRequestConfigImpl {
588
729
  return this.method !== 'GET' && this.method !== 'HEAD';
589
730
  }
590
731
  }
732
+ /**
733
+ * An adapter class for extracting options and entity data from an `HttpRequestConfig`.
734
+ */
735
+ class HttpRequestConfigImpl extends BaseRequestConfigImpl {
736
+ constructor(httpConfig) {
737
+ super(httpConfig);
738
+ this.httpConfig = httpConfig;
739
+ }
740
+ get httpAgent() {
741
+ return this.httpConfig.httpAgent;
742
+ }
743
+ buildRequestOptions() {
744
+ const parsed = this.buildUrl();
745
+ const protocol = parsed.protocol;
746
+ let port = parsed.port;
747
+ if (!port) {
748
+ const isHttps = protocol === 'https:';
749
+ port = isHttps ? '443' : '80';
750
+ }
751
+ return {
752
+ protocol,
753
+ hostname: parsed.hostname,
754
+ port,
755
+ path: parsed.path,
756
+ method: this.method,
757
+ agent: this.httpAgent,
758
+ headers: Object.assign({}, this.headers),
759
+ };
760
+ }
761
+ }
762
+ /**
763
+ * An adapter class for extracting options and entity data from an `Http2RequestConfig`.
764
+ */
765
+ class Http2RequestConfigImpl extends BaseRequestConfigImpl {
766
+ constructor(http2Config) {
767
+ super(http2Config);
768
+ this.http2Config = http2Config;
769
+ }
770
+ get http2SessionHandler() {
771
+ return this.http2Config.http2SessionHandler;
772
+ }
773
+ buildRequestOptions() {
774
+ const parsed = this.buildUrl();
775
+ const protocol = parsed.protocol;
776
+ return {
777
+ protocol,
778
+ path: parsed.path,
779
+ method: this.method,
780
+ headers: Object.assign({}, this.headers),
781
+ };
782
+ }
783
+ }
591
784
  class AuthorizedHttpClient extends HttpClient {
592
785
  constructor(app) {
593
786
  super();
@@ -612,17 +805,35 @@ class AuthorizedHttpClient extends HttpClient {
612
805
  }
613
806
  getToken() {
614
807
  return this.app.INTERNAL.getToken()
615
- .then((accessTokenObj) => {
616
- return accessTokenObj.accessToken;
617
- });
808
+ .then((accessTokenObj) => accessTokenObj.accessToken);
618
809
  }
619
810
  }
620
811
  exports.AuthorizedHttpClient = AuthorizedHttpClient;
812
+ class AuthorizedHttp2Client extends Http2Client {
813
+ constructor(app) {
814
+ super();
815
+ this.app = app;
816
+ }
817
+ send(request) {
818
+ return this.getToken().then((token) => {
819
+ const requestCopy = Object.assign({}, request);
820
+ requestCopy.headers = Object.assign({}, request.headers);
821
+ const authHeader = 'Authorization';
822
+ requestCopy.headers[authHeader] = `Bearer ${token}`;
823
+ return super.send(requestCopy);
824
+ });
825
+ }
826
+ getToken() {
827
+ return this.app.INTERNAL.getToken()
828
+ .then((accessTokenObj) => accessTokenObj.accessToken);
829
+ }
830
+ }
831
+ exports.AuthorizedHttp2Client = AuthorizedHttp2Client;
621
832
  /**
622
833
  * Class that defines all the settings for the backend API endpoint.
623
834
  *
624
835
  * @param endpoint - The Firebase Auth backend endpoint.
625
- * @param httpMethod - The http method for that endpoint.
836
+ * @param httpMethod - The HTTP method for that endpoint.
626
837
  * @constructor
627
838
  */
628
839
  class ApiSettings {
@@ -767,3 +978,36 @@ class ExponentialBackoffPoller extends events_1.EventEmitter {
767
978
  }
768
979
  }
769
980
  exports.ExponentialBackoffPoller = ExponentialBackoffPoller;
981
+ class Http2SessionHandler {
982
+ constructor(url) {
983
+ this.http2Session = this.createSession(url);
984
+ }
985
+ createSession(url) {
986
+ if (!this.http2Session || this.isClosed) {
987
+ const opts = {
988
+ // Set local max concurrent stream limit to respect backend limit
989
+ peerMaxConcurrentStreams: 100,
990
+ ALPNProtocols: ['h2']
991
+ };
992
+ const http2Session = http2.connect(url, opts);
993
+ http2Session.on('goaway', (errorCode, _, opaqueData) => {
994
+ throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_ERROR, `Error while making requests: GOAWAY - ${opaqueData.toString()}, Error code: ${errorCode}`);
995
+ });
996
+ http2Session.on('error', (error) => {
997
+ throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_ERROR, `Error while making requests: ${error}`);
998
+ });
999
+ return http2Session;
1000
+ }
1001
+ return this.http2Session;
1002
+ }
1003
+ get session() {
1004
+ return this.http2Session;
1005
+ }
1006
+ get isClosed() {
1007
+ return this.http2Session.closed;
1008
+ }
1009
+ close() {
1010
+ this.http2Session.close();
1011
+ }
1012
+ }
1013
+ exports.Http2SessionHandler = Http2SessionHandler;