@firebase/storage 0.8.4-pr5646.4594d3fd6 → 0.8.5

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 (64) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/index.browser.cjs.js +1 -1
  3. package/dist/index.esm2017.js +1 -1
  4. package/dist/index.esm5.js +1 -1
  5. package/dist/{index.cjs.js → index.node.cjs.js} +2 -2
  6. package/dist/index.node.cjs.js.map +1 -0
  7. package/dist/node-esm/index.node.esm.js +3351 -0
  8. package/dist/node-esm/index.node.esm.js.map +1 -0
  9. package/dist/node-esm/package.json +1 -0
  10. package/dist/node-esm/src/api.browser.d.ts +17 -0
  11. package/dist/node-esm/src/api.d.ts +184 -0
  12. package/dist/node-esm/src/api.node.d.ts +17 -0
  13. package/dist/node-esm/src/constants.d.ts +20 -0
  14. package/dist/node-esm/src/implementation/async.d.ts +22 -0
  15. package/dist/node-esm/src/implementation/backoff.d.ts +37 -0
  16. package/dist/node-esm/src/implementation/blob.d.ts +34 -0
  17. package/dist/node-esm/src/implementation/connection.d.ts +47 -0
  18. package/dist/node-esm/src/implementation/constants.d.ts +44 -0
  19. package/dist/node-esm/src/implementation/error.d.ts +105 -0
  20. package/dist/node-esm/src/implementation/failrequest.d.ts +29 -0
  21. package/dist/node-esm/src/implementation/fs.d.ts +17 -0
  22. package/dist/node-esm/src/implementation/json.d.ts +7 -0
  23. package/dist/node-esm/src/implementation/list.d.ts +19 -0
  24. package/dist/node-esm/src/implementation/location.d.ts +32 -0
  25. package/dist/node-esm/src/implementation/metadata.d.ts +40 -0
  26. package/dist/node-esm/src/implementation/observer.d.ts +47 -0
  27. package/dist/node-esm/src/implementation/path.d.ts +31 -0
  28. package/dist/node-esm/src/implementation/request.d.ts +47 -0
  29. package/dist/node-esm/src/implementation/requestinfo.d.ts +65 -0
  30. package/dist/node-esm/src/implementation/requests.d.ts +83 -0
  31. package/dist/node-esm/src/implementation/string.d.ts +73 -0
  32. package/dist/node-esm/src/implementation/taskenums.d.ts +77 -0
  33. package/dist/node-esm/src/implementation/type.d.ts +23 -0
  34. package/dist/node-esm/src/implementation/url.d.ts +22 -0
  35. package/dist/node-esm/src/index.d.ts +7 -0
  36. package/dist/node-esm/src/index.node.d.ts +7 -0
  37. package/dist/node-esm/src/list.d.ts +41 -0
  38. package/dist/node-esm/src/metadata.d.ts +27 -0
  39. package/dist/node-esm/src/platform/base64.d.ts +20 -0
  40. package/dist/node-esm/src/platform/browser/base64.d.ts +19 -0
  41. package/dist/node-esm/src/platform/browser/connection.d.ts +39 -0
  42. package/dist/node-esm/src/platform/connection.d.ts +19 -0
  43. package/dist/node-esm/src/platform/node/base64.d.ts +19 -0
  44. package/dist/node-esm/src/platform/node/connection.d.ts +45 -0
  45. package/dist/node-esm/src/public-types.d.ts +433 -0
  46. package/dist/node-esm/src/reference.d.ts +196 -0
  47. package/dist/node-esm/src/service.d.ts +130 -0
  48. package/dist/node-esm/src/task.d.ts +143 -0
  49. package/dist/node-esm/test/browser/blob.test.d.ts +17 -0
  50. package/dist/node-esm/test/browser/connection.test.d.ts +17 -0
  51. package/dist/node-esm/test/integration/integration.test.d.ts +20 -0
  52. package/dist/node-esm/test/unit/connection.d.ts +46 -0
  53. package/dist/node-esm/test/unit/connection.test.d.ts +17 -0
  54. package/dist/node-esm/test/unit/index.test.d.ts +4 -0
  55. package/dist/node-esm/test/unit/location.test.d.ts +1 -0
  56. package/dist/node-esm/test/unit/reference.test.d.ts +1 -0
  57. package/dist/node-esm/test/unit/request.test.d.ts +1 -0
  58. package/dist/node-esm/test/unit/requests.test.d.ts +1 -0
  59. package/dist/node-esm/test/unit/service.test.d.ts +1 -0
  60. package/dist/node-esm/test/unit/string.test.d.ts +1 -0
  61. package/dist/node-esm/test/unit/task.test.d.ts +1 -0
  62. package/dist/node-esm/test/unit/testshared.d.ts +47 -0
  63. package/package.json +17 -7
  64. package/dist/index.cjs.js.map +0 -1
@@ -0,0 +1,3351 @@
1
+ import { getApp, _getProvider, _registerComponent, registerVersion, SDK_VERSION } from '@firebase/app';
2
+ import { FirebaseError, createMockUserToken, getModularInstance } from '@firebase/util';
3
+ import nodeFetch from 'node-fetch';
4
+ import { Component } from '@firebase/component';
5
+
6
+ /**
7
+ * @license
8
+ * Copyright 2017 Google LLC
9
+ *
10
+ * Licensed under the Apache License, Version 2.0 (the "License");
11
+ * you may not use this file except in compliance with the License.
12
+ * You may obtain a copy of the License at
13
+ *
14
+ * http://www.apache.org/licenses/LICENSE-2.0
15
+ *
16
+ * Unless required by applicable law or agreed to in writing, software
17
+ * distributed under the License is distributed on an "AS IS" BASIS,
18
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ * See the License for the specific language governing permissions and
20
+ * limitations under the License.
21
+ */
22
+ /**
23
+ * @fileoverview Constants used in the Firebase Storage library.
24
+ */
25
+ /**
26
+ * Domain name for firebase storage.
27
+ */
28
+ const DEFAULT_HOST = 'firebasestorage.googleapis.com';
29
+ /**
30
+ * The key in Firebase config json for the storage bucket.
31
+ */
32
+ const CONFIG_STORAGE_BUCKET_KEY = 'storageBucket';
33
+ /**
34
+ * 2 minutes
35
+ *
36
+ * The timeout for all operations except upload.
37
+ */
38
+ const DEFAULT_MAX_OPERATION_RETRY_TIME = 2 * 60 * 1000;
39
+ /**
40
+ * 10 minutes
41
+ *
42
+ * The timeout for upload.
43
+ */
44
+ const DEFAULT_MAX_UPLOAD_RETRY_TIME = 10 * 60 * 1000;
45
+
46
+ /**
47
+ * An error returned by the Firebase Storage SDK.
48
+ * @public
49
+ */
50
+ class StorageError extends FirebaseError {
51
+ /**
52
+ * @param code - A StorageErrorCode string to be prefixed with 'storage/' and
53
+ * added to the end of the message.
54
+ * @param message - Error message.
55
+ */
56
+ constructor(code, message) {
57
+ super(prependCode(code), `Firebase Storage: ${message} (${prependCode(code)})`);
58
+ /**
59
+ * Stores custom error data unque to StorageError.
60
+ */
61
+ this.customData = { serverResponse: null };
62
+ this._baseMessage = this.message;
63
+ // Without this, `instanceof StorageError`, in tests for example,
64
+ // returns false.
65
+ Object.setPrototypeOf(this, StorageError.prototype);
66
+ }
67
+ /**
68
+ * Compares a StorageErrorCode against this error's code, filtering out the prefix.
69
+ */
70
+ _codeEquals(code) {
71
+ return prependCode(code) === this.code;
72
+ }
73
+ /**
74
+ * Optional response message that was added by the server.
75
+ */
76
+ get serverResponse() {
77
+ return this.customData.serverResponse;
78
+ }
79
+ set serverResponse(serverResponse) {
80
+ this.customData.serverResponse = serverResponse;
81
+ if (this.customData.serverResponse) {
82
+ this.message = `${this._baseMessage}\n${this.customData.serverResponse}`;
83
+ }
84
+ else {
85
+ this.message = this._baseMessage;
86
+ }
87
+ }
88
+ }
89
+ function prependCode(code) {
90
+ return 'storage/' + code;
91
+ }
92
+ function unknown() {
93
+ const message = 'An unknown error occurred, please check the error payload for ' +
94
+ 'server response.';
95
+ return new StorageError("unknown" /* UNKNOWN */, message);
96
+ }
97
+ function objectNotFound(path) {
98
+ return new StorageError("object-not-found" /* OBJECT_NOT_FOUND */, "Object '" + path + "' does not exist.");
99
+ }
100
+ function quotaExceeded(bucket) {
101
+ return new StorageError("quota-exceeded" /* QUOTA_EXCEEDED */, "Quota for bucket '" +
102
+ bucket +
103
+ "' exceeded, please view quota on " +
104
+ 'https://firebase.google.com/pricing/.');
105
+ }
106
+ function unauthenticated() {
107
+ const message = 'User is not authenticated, please authenticate using Firebase ' +
108
+ 'Authentication and try again.';
109
+ return new StorageError("unauthenticated" /* UNAUTHENTICATED */, message);
110
+ }
111
+ function unauthorizedApp() {
112
+ return new StorageError("unauthorized-app" /* UNAUTHORIZED_APP */, 'This app does not have permission to access Firebase Storage on this project.');
113
+ }
114
+ function unauthorized(path) {
115
+ return new StorageError("unauthorized" /* UNAUTHORIZED */, "User does not have permission to access '" + path + "'.");
116
+ }
117
+ function retryLimitExceeded() {
118
+ return new StorageError("retry-limit-exceeded" /* RETRY_LIMIT_EXCEEDED */, 'Max retry time for operation exceeded, please try again.');
119
+ }
120
+ function canceled() {
121
+ return new StorageError("canceled" /* CANCELED */, 'User canceled the upload/download.');
122
+ }
123
+ function invalidUrl(url) {
124
+ return new StorageError("invalid-url" /* INVALID_URL */, "Invalid URL '" + url + "'.");
125
+ }
126
+ function invalidDefaultBucket(bucket) {
127
+ return new StorageError("invalid-default-bucket" /* INVALID_DEFAULT_BUCKET */, "Invalid default bucket '" + bucket + "'.");
128
+ }
129
+ function noDefaultBucket() {
130
+ return new StorageError("no-default-bucket" /* NO_DEFAULT_BUCKET */, 'No default bucket ' +
131
+ "found. Did you set the '" +
132
+ CONFIG_STORAGE_BUCKET_KEY +
133
+ "' property when initializing the app?");
134
+ }
135
+ function cannotSliceBlob() {
136
+ return new StorageError("cannot-slice-blob" /* CANNOT_SLICE_BLOB */, 'Cannot slice blob for upload. Please retry the upload.');
137
+ }
138
+ function serverFileWrongSize() {
139
+ return new StorageError("server-file-wrong-size" /* SERVER_FILE_WRONG_SIZE */, 'Server recorded incorrect upload file size, please retry the upload.');
140
+ }
141
+ function noDownloadURL() {
142
+ return new StorageError("no-download-url" /* NO_DOWNLOAD_URL */, 'The given file does not have any download URLs.');
143
+ }
144
+ /**
145
+ * @internal
146
+ */
147
+ function invalidArgument(message) {
148
+ return new StorageError("invalid-argument" /* INVALID_ARGUMENT */, message);
149
+ }
150
+ function appDeleted() {
151
+ return new StorageError("app-deleted" /* APP_DELETED */, 'The Firebase app was deleted.');
152
+ }
153
+ /**
154
+ * @param name - The name of the operation that was invalid.
155
+ *
156
+ * @internal
157
+ */
158
+ function invalidRootOperation(name) {
159
+ return new StorageError("invalid-root-operation" /* INVALID_ROOT_OPERATION */, "The operation '" +
160
+ name +
161
+ "' cannot be performed on a root reference, create a non-root " +
162
+ "reference using child, such as .child('file.png').");
163
+ }
164
+ /**
165
+ * @param format - The format that was not valid.
166
+ * @param message - A message describing the format violation.
167
+ */
168
+ function invalidFormat(format, message) {
169
+ return new StorageError("invalid-format" /* INVALID_FORMAT */, "String does not match format '" + format + "': " + message);
170
+ }
171
+ /**
172
+ * @param message - A message describing the internal error.
173
+ */
174
+ function internalError(message) {
175
+ throw new StorageError("internal-error" /* INTERNAL_ERROR */, 'Internal error: ' + message);
176
+ }
177
+
178
+ /**
179
+ * @license
180
+ * Copyright 2017 Google LLC
181
+ *
182
+ * Licensed under the Apache License, Version 2.0 (the "License");
183
+ * you may not use this file except in compliance with the License.
184
+ * You may obtain a copy of the License at
185
+ *
186
+ * http://www.apache.org/licenses/LICENSE-2.0
187
+ *
188
+ * Unless required by applicable law or agreed to in writing, software
189
+ * distributed under the License is distributed on an "AS IS" BASIS,
190
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
191
+ * See the License for the specific language governing permissions and
192
+ * limitations under the License.
193
+ */
194
+ /**
195
+ * Firebase Storage location data.
196
+ *
197
+ * @internal
198
+ */
199
+ class Location {
200
+ constructor(bucket, path) {
201
+ this.bucket = bucket;
202
+ this.path_ = path;
203
+ }
204
+ get path() {
205
+ return this.path_;
206
+ }
207
+ get isRoot() {
208
+ return this.path.length === 0;
209
+ }
210
+ fullServerUrl() {
211
+ const encode = encodeURIComponent;
212
+ return '/b/' + encode(this.bucket) + '/o/' + encode(this.path);
213
+ }
214
+ bucketOnlyServerUrl() {
215
+ const encode = encodeURIComponent;
216
+ return '/b/' + encode(this.bucket) + '/o';
217
+ }
218
+ static makeFromBucketSpec(bucketString, host) {
219
+ let bucketLocation;
220
+ try {
221
+ bucketLocation = Location.makeFromUrl(bucketString, host);
222
+ }
223
+ catch (e) {
224
+ // Not valid URL, use as-is. This lets you put bare bucket names in
225
+ // config.
226
+ return new Location(bucketString, '');
227
+ }
228
+ if (bucketLocation.path === '') {
229
+ return bucketLocation;
230
+ }
231
+ else {
232
+ throw invalidDefaultBucket(bucketString);
233
+ }
234
+ }
235
+ static makeFromUrl(url, host) {
236
+ let location = null;
237
+ const bucketDomain = '([A-Za-z0-9.\\-_]+)';
238
+ function gsModify(loc) {
239
+ if (loc.path.charAt(loc.path.length - 1) === '/') {
240
+ loc.path_ = loc.path_.slice(0, -1);
241
+ }
242
+ }
243
+ const gsPath = '(/(.*))?$';
244
+ const gsRegex = new RegExp('^gs://' + bucketDomain + gsPath, 'i');
245
+ const gsIndices = { bucket: 1, path: 3 };
246
+ function httpModify(loc) {
247
+ loc.path_ = decodeURIComponent(loc.path);
248
+ }
249
+ const version = 'v[A-Za-z0-9_]+';
250
+ const firebaseStorageHost = host.replace(/[.]/g, '\\.');
251
+ const firebaseStoragePath = '(/([^?#]*).*)?$';
252
+ const firebaseStorageRegExp = new RegExp(`^https?://${firebaseStorageHost}/${version}/b/${bucketDomain}/o${firebaseStoragePath}`, 'i');
253
+ const firebaseStorageIndices = { bucket: 1, path: 3 };
254
+ const cloudStorageHost = host === DEFAULT_HOST
255
+ ? '(?:storage.googleapis.com|storage.cloud.google.com)'
256
+ : host;
257
+ const cloudStoragePath = '([^?#]*)';
258
+ const cloudStorageRegExp = new RegExp(`^https?://${cloudStorageHost}/${bucketDomain}/${cloudStoragePath}`, 'i');
259
+ const cloudStorageIndices = { bucket: 1, path: 2 };
260
+ const groups = [
261
+ { regex: gsRegex, indices: gsIndices, postModify: gsModify },
262
+ {
263
+ regex: firebaseStorageRegExp,
264
+ indices: firebaseStorageIndices,
265
+ postModify: httpModify
266
+ },
267
+ {
268
+ regex: cloudStorageRegExp,
269
+ indices: cloudStorageIndices,
270
+ postModify: httpModify
271
+ }
272
+ ];
273
+ for (let i = 0; i < groups.length; i++) {
274
+ const group = groups[i];
275
+ const captures = group.regex.exec(url);
276
+ if (captures) {
277
+ const bucketValue = captures[group.indices.bucket];
278
+ let pathValue = captures[group.indices.path];
279
+ if (!pathValue) {
280
+ pathValue = '';
281
+ }
282
+ location = new Location(bucketValue, pathValue);
283
+ group.postModify(location);
284
+ break;
285
+ }
286
+ }
287
+ if (location == null) {
288
+ throw invalidUrl(url);
289
+ }
290
+ return location;
291
+ }
292
+ }
293
+
294
+ /**
295
+ * A request whose promise always fails.
296
+ */
297
+ class FailRequest {
298
+ constructor(error) {
299
+ this.promise_ = Promise.reject(error);
300
+ }
301
+ /** @inheritDoc */
302
+ getPromise() {
303
+ return this.promise_;
304
+ }
305
+ /** @inheritDoc */
306
+ cancel(_appDelete = false) { }
307
+ }
308
+
309
+ /**
310
+ * @license
311
+ * Copyright 2017 Google LLC
312
+ *
313
+ * Licensed under the Apache License, Version 2.0 (the "License");
314
+ * you may not use this file except in compliance with the License.
315
+ * You may obtain a copy of the License at
316
+ *
317
+ * http://www.apache.org/licenses/LICENSE-2.0
318
+ *
319
+ * Unless required by applicable law or agreed to in writing, software
320
+ * distributed under the License is distributed on an "AS IS" BASIS,
321
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
322
+ * See the License for the specific language governing permissions and
323
+ * limitations under the License.
324
+ */
325
+ /**
326
+ * @param f May be invoked
327
+ * before the function returns.
328
+ * @param callback Get all the arguments passed to the function
329
+ * passed to f, including the initial boolean.
330
+ */
331
+ function start(f,
332
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
333
+ callback, timeout) {
334
+ // TODO(andysoto): make this code cleaner (probably refactor into an actual
335
+ // type instead of a bunch of functions with state shared in the closure)
336
+ let waitSeconds = 1;
337
+ // Would type this as "number" but that doesn't work for Node so ¯\_(ツ)_/¯
338
+ // TODO: find a way to exclude Node type definition for storage because storage only works in browser
339
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
340
+ let timeoutId = null;
341
+ let hitTimeout = false;
342
+ let cancelState = 0;
343
+ function canceled() {
344
+ return cancelState === 2;
345
+ }
346
+ let triggeredCallback = false;
347
+ function triggerCallback(...args) {
348
+ if (!triggeredCallback) {
349
+ triggeredCallback = true;
350
+ callback.apply(null, args);
351
+ }
352
+ }
353
+ function callWithDelay(millis) {
354
+ timeoutId = setTimeout(() => {
355
+ timeoutId = null;
356
+ f(handler, canceled());
357
+ }, millis);
358
+ }
359
+ function handler(success, ...args) {
360
+ if (triggeredCallback) {
361
+ return;
362
+ }
363
+ if (success) {
364
+ triggerCallback.call(null, success, ...args);
365
+ return;
366
+ }
367
+ const mustStop = canceled() || hitTimeout;
368
+ if (mustStop) {
369
+ triggerCallback.call(null, success, ...args);
370
+ return;
371
+ }
372
+ if (waitSeconds < 64) {
373
+ /* TODO(andysoto): don't back off so quickly if we know we're offline. */
374
+ waitSeconds *= 2;
375
+ }
376
+ let waitMillis;
377
+ if (cancelState === 1) {
378
+ cancelState = 2;
379
+ waitMillis = 0;
380
+ }
381
+ else {
382
+ waitMillis = (waitSeconds + Math.random()) * 1000;
383
+ }
384
+ callWithDelay(waitMillis);
385
+ }
386
+ let stopped = false;
387
+ function stop(wasTimeout) {
388
+ if (stopped) {
389
+ return;
390
+ }
391
+ stopped = true;
392
+ if (triggeredCallback) {
393
+ return;
394
+ }
395
+ if (timeoutId !== null) {
396
+ if (!wasTimeout) {
397
+ cancelState = 2;
398
+ }
399
+ clearTimeout(timeoutId);
400
+ callWithDelay(0);
401
+ }
402
+ else {
403
+ if (!wasTimeout) {
404
+ cancelState = 1;
405
+ }
406
+ }
407
+ }
408
+ callWithDelay(0);
409
+ setTimeout(() => {
410
+ hitTimeout = true;
411
+ stop(true);
412
+ }, timeout);
413
+ return stop;
414
+ }
415
+ /**
416
+ * Stops the retry loop from repeating.
417
+ * If the function is currently "in between" retries, it is invoked immediately
418
+ * with the second parameter as "true". Otherwise, it will be invoked once more
419
+ * after the current invocation finishes iff the current invocation would have
420
+ * triggered another retry.
421
+ */
422
+ function stop(id) {
423
+ id(false);
424
+ }
425
+
426
+ /**
427
+ * @license
428
+ * Copyright 2017 Google LLC
429
+ *
430
+ * Licensed under the Apache License, Version 2.0 (the "License");
431
+ * you may not use this file except in compliance with the License.
432
+ * You may obtain a copy of the License at
433
+ *
434
+ * http://www.apache.org/licenses/LICENSE-2.0
435
+ *
436
+ * Unless required by applicable law or agreed to in writing, software
437
+ * distributed under the License is distributed on an "AS IS" BASIS,
438
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
439
+ * See the License for the specific language governing permissions and
440
+ * limitations under the License.
441
+ */
442
+ function isJustDef(p) {
443
+ return p !== void 0;
444
+ }
445
+ // eslint-disable-next-line @typescript-eslint/ban-types
446
+ function isFunction(p) {
447
+ return typeof p === 'function';
448
+ }
449
+ function isNonArrayObject(p) {
450
+ return typeof p === 'object' && !Array.isArray(p);
451
+ }
452
+ function isString(p) {
453
+ return typeof p === 'string' || p instanceof String;
454
+ }
455
+ function isNativeBlob(p) {
456
+ return isNativeBlobDefined() && p instanceof Blob;
457
+ }
458
+ function isNativeBlobDefined() {
459
+ return typeof Blob !== 'undefined';
460
+ }
461
+ function validateNumber(argument, minValue, maxValue, value) {
462
+ if (value < minValue) {
463
+ throw invalidArgument(`Invalid value for '${argument}'. Expected ${minValue} or greater.`);
464
+ }
465
+ if (value > maxValue) {
466
+ throw invalidArgument(`Invalid value for '${argument}'. Expected ${maxValue} or less.`);
467
+ }
468
+ }
469
+
470
+ /**
471
+ * @license
472
+ * Copyright 2017 Google LLC
473
+ *
474
+ * Licensed under the Apache License, Version 2.0 (the "License");
475
+ * you may not use this file except in compliance with the License.
476
+ * You may obtain a copy of the License at
477
+ *
478
+ * http://www.apache.org/licenses/LICENSE-2.0
479
+ *
480
+ * Unless required by applicable law or agreed to in writing, software
481
+ * distributed under the License is distributed on an "AS IS" BASIS,
482
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
483
+ * See the License for the specific language governing permissions and
484
+ * limitations under the License.
485
+ */
486
+ function makeUrl(urlPart, host, protocol) {
487
+ let origin = host;
488
+ if (protocol == null) {
489
+ origin = `https://${host}`;
490
+ }
491
+ return `${protocol}://${origin}/v0${urlPart}`;
492
+ }
493
+ function makeQueryString(params) {
494
+ const encode = encodeURIComponent;
495
+ let queryPart = '?';
496
+ for (const key in params) {
497
+ if (params.hasOwnProperty(key)) {
498
+ const nextPart = encode(key) + '=' + encode(params[key]);
499
+ queryPart = queryPart + nextPart + '&';
500
+ }
501
+ }
502
+ // Chop off the extra '&' or '?' on the end
503
+ queryPart = queryPart.slice(0, -1);
504
+ return queryPart;
505
+ }
506
+
507
+ /**
508
+ * @license
509
+ * Copyright 2017 Google LLC
510
+ *
511
+ * Licensed under the Apache License, Version 2.0 (the "License");
512
+ * you may not use this file except in compliance with the License.
513
+ * You may obtain a copy of the License at
514
+ *
515
+ * http://www.apache.org/licenses/LICENSE-2.0
516
+ *
517
+ * Unless required by applicable law or agreed to in writing, software
518
+ * distributed under the License is distributed on an "AS IS" BASIS,
519
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
520
+ * See the License for the specific language governing permissions and
521
+ * limitations under the License.
522
+ */
523
+ /**
524
+ * Error codes for requests made by the the XhrIo wrapper.
525
+ */
526
+ var ErrorCode;
527
+ (function (ErrorCode) {
528
+ ErrorCode[ErrorCode["NO_ERROR"] = 0] = "NO_ERROR";
529
+ ErrorCode[ErrorCode["NETWORK_ERROR"] = 1] = "NETWORK_ERROR";
530
+ ErrorCode[ErrorCode["ABORT"] = 2] = "ABORT";
531
+ })(ErrorCode || (ErrorCode = {}));
532
+
533
+ /**
534
+ * @license
535
+ * Copyright 2017 Google LLC
536
+ *
537
+ * Licensed under the Apache License, Version 2.0 (the "License");
538
+ * you may not use this file except in compliance with the License.
539
+ * You may obtain a copy of the License at
540
+ *
541
+ * http://www.apache.org/licenses/LICENSE-2.0
542
+ *
543
+ * Unless required by applicable law or agreed to in writing, software
544
+ * distributed under the License is distributed on an "AS IS" BASIS,
545
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
546
+ * See the License for the specific language governing permissions and
547
+ * limitations under the License.
548
+ */
549
+ class NetworkRequest {
550
+ constructor(url_, method_, headers_, body_, successCodes_, additionalRetryCodes_, callback_, errorCallback_, timeout_, progressCallback_, connectionFactory_) {
551
+ this.url_ = url_;
552
+ this.method_ = method_;
553
+ this.headers_ = headers_;
554
+ this.body_ = body_;
555
+ this.successCodes_ = successCodes_;
556
+ this.additionalRetryCodes_ = additionalRetryCodes_;
557
+ this.callback_ = callback_;
558
+ this.errorCallback_ = errorCallback_;
559
+ this.timeout_ = timeout_;
560
+ this.progressCallback_ = progressCallback_;
561
+ this.connectionFactory_ = connectionFactory_;
562
+ this.pendingConnection_ = null;
563
+ this.backoffId_ = null;
564
+ this.canceled_ = false;
565
+ this.appDelete_ = false;
566
+ this.promise_ = new Promise((resolve, reject) => {
567
+ this.resolve_ = resolve;
568
+ this.reject_ = reject;
569
+ this.start_();
570
+ });
571
+ }
572
+ /**
573
+ * Actually starts the retry loop.
574
+ */
575
+ start_() {
576
+ const doTheRequest = (backoffCallback, canceled) => {
577
+ if (canceled) {
578
+ backoffCallback(false, new RequestEndStatus(false, null, true));
579
+ return;
580
+ }
581
+ const connection = this.connectionFactory_();
582
+ this.pendingConnection_ = connection;
583
+ const progressListener = progressEvent => {
584
+ const loaded = progressEvent.loaded;
585
+ const total = progressEvent.lengthComputable
586
+ ? progressEvent.total
587
+ : -1;
588
+ if (this.progressCallback_ !== null) {
589
+ this.progressCallback_(loaded, total);
590
+ }
591
+ };
592
+ if (this.progressCallback_ !== null) {
593
+ connection.addUploadProgressListener(progressListener);
594
+ }
595
+ // connection.send() never rejects, so we don't need to have a error handler or use catch on the returned promise.
596
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
597
+ connection
598
+ .send(this.url_, this.method_, this.body_, this.headers_)
599
+ .then(() => {
600
+ if (this.progressCallback_ !== null) {
601
+ connection.removeUploadProgressListener(progressListener);
602
+ }
603
+ this.pendingConnection_ = null;
604
+ const hitServer = connection.getErrorCode() === ErrorCode.NO_ERROR;
605
+ const status = connection.getStatus();
606
+ if (!hitServer || this.isRetryStatusCode_(status)) {
607
+ const wasCanceled = connection.getErrorCode() === ErrorCode.ABORT;
608
+ backoffCallback(false, new RequestEndStatus(false, null, wasCanceled));
609
+ return;
610
+ }
611
+ const successCode = this.successCodes_.indexOf(status) !== -1;
612
+ backoffCallback(true, new RequestEndStatus(successCode, connection));
613
+ });
614
+ };
615
+ /**
616
+ * @param requestWentThrough - True if the request eventually went
617
+ * through, false if it hit the retry limit or was canceled.
618
+ */
619
+ const backoffDone = (requestWentThrough, status) => {
620
+ const resolve = this.resolve_;
621
+ const reject = this.reject_;
622
+ const connection = status.connection;
623
+ if (status.wasSuccessCode) {
624
+ try {
625
+ const result = this.callback_(connection, connection.getResponseText());
626
+ if (isJustDef(result)) {
627
+ resolve(result);
628
+ }
629
+ else {
630
+ resolve();
631
+ }
632
+ }
633
+ catch (e) {
634
+ reject(e);
635
+ }
636
+ }
637
+ else {
638
+ if (connection !== null) {
639
+ const err = unknown();
640
+ err.serverResponse = connection.getResponseText();
641
+ if (this.errorCallback_) {
642
+ reject(this.errorCallback_(connection, err));
643
+ }
644
+ else {
645
+ reject(err);
646
+ }
647
+ }
648
+ else {
649
+ if (status.canceled) {
650
+ const err = this.appDelete_ ? appDeleted() : canceled();
651
+ reject(err);
652
+ }
653
+ else {
654
+ const err = retryLimitExceeded();
655
+ reject(err);
656
+ }
657
+ }
658
+ }
659
+ };
660
+ if (this.canceled_) {
661
+ backoffDone(false, new RequestEndStatus(false, null, true));
662
+ }
663
+ else {
664
+ this.backoffId_ = start(doTheRequest, backoffDone, this.timeout_);
665
+ }
666
+ }
667
+ /** @inheritDoc */
668
+ getPromise() {
669
+ return this.promise_;
670
+ }
671
+ /** @inheritDoc */
672
+ cancel(appDelete) {
673
+ this.canceled_ = true;
674
+ this.appDelete_ = appDelete || false;
675
+ if (this.backoffId_ !== null) {
676
+ stop(this.backoffId_);
677
+ }
678
+ if (this.pendingConnection_ !== null) {
679
+ this.pendingConnection_.abort();
680
+ }
681
+ }
682
+ isRetryStatusCode_(status) {
683
+ // The codes for which to retry came from this page:
684
+ // https://cloud.google.com/storage/docs/exponential-backoff
685
+ const isFiveHundredCode = status >= 500 && status < 600;
686
+ const extraRetryCodes = [
687
+ // Request Timeout: web server didn't receive full request in time.
688
+ 408,
689
+ // Too Many Requests: you're getting rate-limited, basically.
690
+ 429
691
+ ];
692
+ const isExtraRetryCode = extraRetryCodes.indexOf(status) !== -1;
693
+ const isRequestSpecificRetryCode = this.additionalRetryCodes_.indexOf(status) !== -1;
694
+ return isFiveHundredCode || isExtraRetryCode || isRequestSpecificRetryCode;
695
+ }
696
+ }
697
+ /**
698
+ * A collection of information about the result of a network request.
699
+ * @param opt_canceled - Defaults to false.
700
+ */
701
+ class RequestEndStatus {
702
+ constructor(wasSuccessCode, connection, canceled) {
703
+ this.wasSuccessCode = wasSuccessCode;
704
+ this.connection = connection;
705
+ this.canceled = !!canceled;
706
+ }
707
+ }
708
+ function addAuthHeader_(headers, authToken) {
709
+ if (authToken !== null && authToken.length > 0) {
710
+ headers['Authorization'] = 'Firebase ' + authToken;
711
+ }
712
+ }
713
+ function addVersionHeader_(headers, firebaseVersion) {
714
+ headers['X-Firebase-Storage-Version'] =
715
+ 'webjs/' + (firebaseVersion !== null && firebaseVersion !== void 0 ? firebaseVersion : 'AppManager');
716
+ }
717
+ function addGmpidHeader_(headers, appId) {
718
+ if (appId) {
719
+ headers['X-Firebase-GMPID'] = appId;
720
+ }
721
+ }
722
+ function addAppCheckHeader_(headers, appCheckToken) {
723
+ if (appCheckToken !== null) {
724
+ headers['X-Firebase-AppCheck'] = appCheckToken;
725
+ }
726
+ }
727
+ function makeRequest(requestInfo, appId, authToken, appCheckToken, requestFactory, firebaseVersion) {
728
+ const queryPart = makeQueryString(requestInfo.urlParams);
729
+ const url = requestInfo.url + queryPart;
730
+ const headers = Object.assign({}, requestInfo.headers);
731
+ addGmpidHeader_(headers, appId);
732
+ addAuthHeader_(headers, authToken);
733
+ addVersionHeader_(headers, firebaseVersion);
734
+ addAppCheckHeader_(headers, appCheckToken);
735
+ return new NetworkRequest(url, requestInfo.method, headers, requestInfo.body, requestInfo.successCodes, requestInfo.additionalRetryCodes, requestInfo.handler, requestInfo.errorHandler, requestInfo.timeout, requestInfo.progressCallback, requestFactory);
736
+ }
737
+
738
+ /**
739
+ * @license
740
+ * Copyright 2017 Google LLC
741
+ *
742
+ * Licensed under the Apache License, Version 2.0 (the "License");
743
+ * you may not use this file except in compliance with the License.
744
+ * You may obtain a copy of the License at
745
+ *
746
+ * http://www.apache.org/licenses/LICENSE-2.0
747
+ *
748
+ * Unless required by applicable law or agreed to in writing, software
749
+ * distributed under the License is distributed on an "AS IS" BASIS,
750
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
751
+ * See the License for the specific language governing permissions and
752
+ * limitations under the License.
753
+ */
754
+ function getBlobBuilder() {
755
+ if (typeof BlobBuilder !== 'undefined') {
756
+ return BlobBuilder;
757
+ }
758
+ else if (typeof WebKitBlobBuilder !== 'undefined') {
759
+ return WebKitBlobBuilder;
760
+ }
761
+ else {
762
+ return undefined;
763
+ }
764
+ }
765
+ /**
766
+ * Concatenates one or more values together and converts them to a Blob.
767
+ *
768
+ * @param args The values that will make up the resulting blob.
769
+ * @return The blob.
770
+ */
771
+ function getBlob(...args) {
772
+ const BlobBuilder = getBlobBuilder();
773
+ if (BlobBuilder !== undefined) {
774
+ const bb = new BlobBuilder();
775
+ for (let i = 0; i < args.length; i++) {
776
+ bb.append(args[i]);
777
+ }
778
+ return bb.getBlob();
779
+ }
780
+ else {
781
+ if (isNativeBlobDefined()) {
782
+ return new Blob(args);
783
+ }
784
+ else {
785
+ throw new StorageError("unsupported-environment" /* UNSUPPORTED_ENVIRONMENT */, "This browser doesn't seem to support creating Blobs");
786
+ }
787
+ }
788
+ }
789
+ /**
790
+ * Slices the blob. The returned blob contains data from the start byte
791
+ * (inclusive) till the end byte (exclusive). Negative indices cannot be used.
792
+ *
793
+ * @param blob The blob to be sliced.
794
+ * @param start Index of the starting byte.
795
+ * @param end Index of the ending byte.
796
+ * @return The blob slice or null if not supported.
797
+ */
798
+ function sliceBlob(blob, start, end) {
799
+ if (blob.webkitSlice) {
800
+ return blob.webkitSlice(start, end);
801
+ }
802
+ else if (blob.mozSlice) {
803
+ return blob.mozSlice(start, end);
804
+ }
805
+ else if (blob.slice) {
806
+ return blob.slice(start, end);
807
+ }
808
+ return null;
809
+ }
810
+
811
+ /**
812
+ * @license
813
+ * Copyright 2021 Google LLC
814
+ *
815
+ * Licensed under the Apache License, Version 2.0 (the "License");
816
+ * you may not use this file except in compliance with the License.
817
+ * You may obtain a copy of the License at
818
+ *
819
+ * http://www.apache.org/licenses/LICENSE-2.0
820
+ *
821
+ * Unless required by applicable law or agreed to in writing, software
822
+ * distributed under the License is distributed on an "AS IS" BASIS,
823
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
824
+ * See the License for the specific language governing permissions and
825
+ * limitations under the License.
826
+ */
827
+ /** Converts a Base64 encoded string to a binary string. */
828
+ function decodeBase64(encoded) {
829
+ // Node actually doesn't validate base64 strings.
830
+ // A quick sanity check that is not a fool-proof validation
831
+ if (/[^-A-Za-z0-9+/=]/.test(encoded)) {
832
+ throw invalidFormat('base64', 'Invalid character found');
833
+ }
834
+ return Buffer.from(encoded, 'base64').toString('binary');
835
+ }
836
+
837
+ /**
838
+ * @license
839
+ * Copyright 2017 Google LLC
840
+ *
841
+ * Licensed under the Apache License, Version 2.0 (the "License");
842
+ * you may not use this file except in compliance with the License.
843
+ * You may obtain a copy of the License at
844
+ *
845
+ * http://www.apache.org/licenses/LICENSE-2.0
846
+ *
847
+ * Unless required by applicable law or agreed to in writing, software
848
+ * distributed under the License is distributed on an "AS IS" BASIS,
849
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
850
+ * See the License for the specific language governing permissions and
851
+ * limitations under the License.
852
+ */
853
+ /**
854
+ * An enumeration of the possible string formats for upload.
855
+ * @public
856
+ */
857
+ const StringFormat = {
858
+ /**
859
+ * Indicates the string should be interpreted "raw", that is, as normal text.
860
+ * The string will be interpreted as UTF-16, then uploaded as a UTF-8 byte
861
+ * sequence.
862
+ * Example: The string 'Hello! \\ud83d\\ude0a' becomes the byte sequence
863
+ * 48 65 6c 6c 6f 21 20 f0 9f 98 8a
864
+ */
865
+ RAW: 'raw',
866
+ /**
867
+ * Indicates the string should be interpreted as base64-encoded data.
868
+ * Padding characters (trailing '='s) are optional.
869
+ * Example: The string 'rWmO++E6t7/rlw==' becomes the byte sequence
870
+ * ad 69 8e fb e1 3a b7 bf eb 97
871
+ */
872
+ BASE64: 'base64',
873
+ /**
874
+ * Indicates the string should be interpreted as base64url-encoded data.
875
+ * Padding characters (trailing '='s) are optional.
876
+ * Example: The string 'rWmO--E6t7_rlw==' becomes the byte sequence
877
+ * ad 69 8e fb e1 3a b7 bf eb 97
878
+ */
879
+ BASE64URL: 'base64url',
880
+ /**
881
+ * Indicates the string is a data URL, such as one obtained from
882
+ * canvas.toDataURL().
883
+ * Example: the string 'data:application/octet-stream;base64,aaaa'
884
+ * becomes the byte sequence
885
+ * 69 a6 9a
886
+ * (the content-type "application/octet-stream" is also applied, but can
887
+ * be overridden in the metadata object).
888
+ */
889
+ DATA_URL: 'data_url'
890
+ };
891
+ class StringData {
892
+ constructor(data, contentType) {
893
+ this.data = data;
894
+ this.contentType = contentType || null;
895
+ }
896
+ }
897
+ /**
898
+ * @internal
899
+ */
900
+ function dataFromString(format, stringData) {
901
+ switch (format) {
902
+ case StringFormat.RAW:
903
+ return new StringData(utf8Bytes_(stringData));
904
+ case StringFormat.BASE64:
905
+ case StringFormat.BASE64URL:
906
+ return new StringData(base64Bytes_(format, stringData));
907
+ case StringFormat.DATA_URL:
908
+ return new StringData(dataURLBytes_(stringData), dataURLContentType_(stringData));
909
+ // do nothing
910
+ }
911
+ // assert(false);
912
+ throw unknown();
913
+ }
914
+ function utf8Bytes_(value) {
915
+ const b = [];
916
+ for (let i = 0; i < value.length; i++) {
917
+ let c = value.charCodeAt(i);
918
+ if (c <= 127) {
919
+ b.push(c);
920
+ }
921
+ else {
922
+ if (c <= 2047) {
923
+ b.push(192 | (c >> 6), 128 | (c & 63));
924
+ }
925
+ else {
926
+ if ((c & 64512) === 55296) {
927
+ // The start of a surrogate pair.
928
+ const valid = i < value.length - 1 && (value.charCodeAt(i + 1) & 64512) === 56320;
929
+ if (!valid) {
930
+ // The second surrogate wasn't there.
931
+ b.push(239, 191, 189);
932
+ }
933
+ else {
934
+ const hi = c;
935
+ const lo = value.charCodeAt(++i);
936
+ c = 65536 | ((hi & 1023) << 10) | (lo & 1023);
937
+ b.push(240 | (c >> 18), 128 | ((c >> 12) & 63), 128 | ((c >> 6) & 63), 128 | (c & 63));
938
+ }
939
+ }
940
+ else {
941
+ if ((c & 64512) === 56320) {
942
+ // Invalid low surrogate.
943
+ b.push(239, 191, 189);
944
+ }
945
+ else {
946
+ b.push(224 | (c >> 12), 128 | ((c >> 6) & 63), 128 | (c & 63));
947
+ }
948
+ }
949
+ }
950
+ }
951
+ }
952
+ return new Uint8Array(b);
953
+ }
954
+ function percentEncodedBytes_(value) {
955
+ let decoded;
956
+ try {
957
+ decoded = decodeURIComponent(value);
958
+ }
959
+ catch (e) {
960
+ throw invalidFormat(StringFormat.DATA_URL, 'Malformed data URL.');
961
+ }
962
+ return utf8Bytes_(decoded);
963
+ }
964
+ function base64Bytes_(format, value) {
965
+ switch (format) {
966
+ case StringFormat.BASE64: {
967
+ const hasMinus = value.indexOf('-') !== -1;
968
+ const hasUnder = value.indexOf('_') !== -1;
969
+ if (hasMinus || hasUnder) {
970
+ const invalidChar = hasMinus ? '-' : '_';
971
+ throw invalidFormat(format, "Invalid character '" +
972
+ invalidChar +
973
+ "' found: is it base64url encoded?");
974
+ }
975
+ break;
976
+ }
977
+ case StringFormat.BASE64URL: {
978
+ const hasPlus = value.indexOf('+') !== -1;
979
+ const hasSlash = value.indexOf('/') !== -1;
980
+ if (hasPlus || hasSlash) {
981
+ const invalidChar = hasPlus ? '+' : '/';
982
+ throw invalidFormat(format, "Invalid character '" + invalidChar + "' found: is it base64 encoded?");
983
+ }
984
+ value = value.replace(/-/g, '+').replace(/_/g, '/');
985
+ break;
986
+ }
987
+ // do nothing
988
+ }
989
+ let bytes;
990
+ try {
991
+ bytes = decodeBase64(value);
992
+ }
993
+ catch (e) {
994
+ throw invalidFormat(format, 'Invalid character found');
995
+ }
996
+ const array = new Uint8Array(bytes.length);
997
+ for (let i = 0; i < bytes.length; i++) {
998
+ array[i] = bytes.charCodeAt(i);
999
+ }
1000
+ return array;
1001
+ }
1002
+ class DataURLParts {
1003
+ constructor(dataURL) {
1004
+ this.base64 = false;
1005
+ this.contentType = null;
1006
+ const matches = dataURL.match(/^data:([^,]+)?,/);
1007
+ if (matches === null) {
1008
+ throw invalidFormat(StringFormat.DATA_URL, "Must be formatted 'data:[<mediatype>][;base64],<data>");
1009
+ }
1010
+ const middle = matches[1] || null;
1011
+ if (middle != null) {
1012
+ this.base64 = endsWith(middle, ';base64');
1013
+ this.contentType = this.base64
1014
+ ? middle.substring(0, middle.length - ';base64'.length)
1015
+ : middle;
1016
+ }
1017
+ this.rest = dataURL.substring(dataURL.indexOf(',') + 1);
1018
+ }
1019
+ }
1020
+ function dataURLBytes_(dataUrl) {
1021
+ const parts = new DataURLParts(dataUrl);
1022
+ if (parts.base64) {
1023
+ return base64Bytes_(StringFormat.BASE64, parts.rest);
1024
+ }
1025
+ else {
1026
+ return percentEncodedBytes_(parts.rest);
1027
+ }
1028
+ }
1029
+ function dataURLContentType_(dataUrl) {
1030
+ const parts = new DataURLParts(dataUrl);
1031
+ return parts.contentType;
1032
+ }
1033
+ function endsWith(s, end) {
1034
+ const longEnough = s.length >= end.length;
1035
+ if (!longEnough) {
1036
+ return false;
1037
+ }
1038
+ return s.substring(s.length - end.length) === end;
1039
+ }
1040
+
1041
+ /**
1042
+ * @license
1043
+ * Copyright 2017 Google LLC
1044
+ *
1045
+ * Licensed under the Apache License, Version 2.0 (the "License");
1046
+ * you may not use this file except in compliance with the License.
1047
+ * You may obtain a copy of the License at
1048
+ *
1049
+ * http://www.apache.org/licenses/LICENSE-2.0
1050
+ *
1051
+ * Unless required by applicable law or agreed to in writing, software
1052
+ * distributed under the License is distributed on an "AS IS" BASIS,
1053
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1054
+ * See the License for the specific language governing permissions and
1055
+ * limitations under the License.
1056
+ */
1057
+ /**
1058
+ * @param opt_elideCopy - If true, doesn't copy mutable input data
1059
+ * (e.g. Uint8Arrays). Pass true only if you know the objects will not be
1060
+ * modified after this blob's construction.
1061
+ *
1062
+ * @internal
1063
+ */
1064
+ class FbsBlob {
1065
+ constructor(data, elideCopy) {
1066
+ let size = 0;
1067
+ let blobType = '';
1068
+ if (isNativeBlob(data)) {
1069
+ this.data_ = data;
1070
+ size = data.size;
1071
+ blobType = data.type;
1072
+ }
1073
+ else if (data instanceof ArrayBuffer) {
1074
+ if (elideCopy) {
1075
+ this.data_ = new Uint8Array(data);
1076
+ }
1077
+ else {
1078
+ this.data_ = new Uint8Array(data.byteLength);
1079
+ this.data_.set(new Uint8Array(data));
1080
+ }
1081
+ size = this.data_.length;
1082
+ }
1083
+ else if (data instanceof Uint8Array) {
1084
+ if (elideCopy) {
1085
+ this.data_ = data;
1086
+ }
1087
+ else {
1088
+ this.data_ = new Uint8Array(data.length);
1089
+ this.data_.set(data);
1090
+ }
1091
+ size = data.length;
1092
+ }
1093
+ this.size_ = size;
1094
+ this.type_ = blobType;
1095
+ }
1096
+ size() {
1097
+ return this.size_;
1098
+ }
1099
+ type() {
1100
+ return this.type_;
1101
+ }
1102
+ slice(startByte, endByte) {
1103
+ if (isNativeBlob(this.data_)) {
1104
+ const realBlob = this.data_;
1105
+ const sliced = sliceBlob(realBlob, startByte, endByte);
1106
+ if (sliced === null) {
1107
+ return null;
1108
+ }
1109
+ return new FbsBlob(sliced);
1110
+ }
1111
+ else {
1112
+ const slice = new Uint8Array(this.data_.buffer, startByte, endByte - startByte);
1113
+ return new FbsBlob(slice, true);
1114
+ }
1115
+ }
1116
+ static getBlob(...args) {
1117
+ if (isNativeBlobDefined()) {
1118
+ const blobby = args.map((val) => {
1119
+ if (val instanceof FbsBlob) {
1120
+ return val.data_;
1121
+ }
1122
+ else {
1123
+ return val;
1124
+ }
1125
+ });
1126
+ return new FbsBlob(getBlob.apply(null, blobby));
1127
+ }
1128
+ else {
1129
+ const uint8Arrays = args.map((val) => {
1130
+ if (isString(val)) {
1131
+ return dataFromString(StringFormat.RAW, val).data;
1132
+ }
1133
+ else {
1134
+ // Blobs don't exist, so this has to be a Uint8Array.
1135
+ return val.data_;
1136
+ }
1137
+ });
1138
+ let finalLength = 0;
1139
+ uint8Arrays.forEach((array) => {
1140
+ finalLength += array.byteLength;
1141
+ });
1142
+ const merged = new Uint8Array(finalLength);
1143
+ let index = 0;
1144
+ uint8Arrays.forEach((array) => {
1145
+ for (let i = 0; i < array.length; i++) {
1146
+ merged[index++] = array[i];
1147
+ }
1148
+ });
1149
+ return new FbsBlob(merged, true);
1150
+ }
1151
+ }
1152
+ uploadData() {
1153
+ return this.data_;
1154
+ }
1155
+ }
1156
+
1157
+ /**
1158
+ * @license
1159
+ * Copyright 2017 Google LLC
1160
+ *
1161
+ * Licensed under the Apache License, Version 2.0 (the "License");
1162
+ * you may not use this file except in compliance with the License.
1163
+ * You may obtain a copy of the License at
1164
+ *
1165
+ * http://www.apache.org/licenses/LICENSE-2.0
1166
+ *
1167
+ * Unless required by applicable law or agreed to in writing, software
1168
+ * distributed under the License is distributed on an "AS IS" BASIS,
1169
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1170
+ * See the License for the specific language governing permissions and
1171
+ * limitations under the License.
1172
+ */
1173
+ /**
1174
+ * Returns the Object resulting from parsing the given JSON, or null if the
1175
+ * given string does not represent a JSON object.
1176
+ */
1177
+ function jsonObjectOrNull(s) {
1178
+ let obj;
1179
+ try {
1180
+ obj = JSON.parse(s);
1181
+ }
1182
+ catch (e) {
1183
+ return null;
1184
+ }
1185
+ if (isNonArrayObject(obj)) {
1186
+ return obj;
1187
+ }
1188
+ else {
1189
+ return null;
1190
+ }
1191
+ }
1192
+
1193
+ /**
1194
+ * @license
1195
+ * Copyright 2017 Google LLC
1196
+ *
1197
+ * Licensed under the Apache License, Version 2.0 (the "License");
1198
+ * you may not use this file except in compliance with the License.
1199
+ * You may obtain a copy of the License at
1200
+ *
1201
+ * http://www.apache.org/licenses/LICENSE-2.0
1202
+ *
1203
+ * Unless required by applicable law or agreed to in writing, software
1204
+ * distributed under the License is distributed on an "AS IS" BASIS,
1205
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1206
+ * See the License for the specific language governing permissions and
1207
+ * limitations under the License.
1208
+ */
1209
+ /**
1210
+ * @fileoverview Contains helper methods for manipulating paths.
1211
+ */
1212
+ /**
1213
+ * @return Null if the path is already at the root.
1214
+ */
1215
+ function parent(path) {
1216
+ if (path.length === 0) {
1217
+ return null;
1218
+ }
1219
+ const index = path.lastIndexOf('/');
1220
+ if (index === -1) {
1221
+ return '';
1222
+ }
1223
+ const newPath = path.slice(0, index);
1224
+ return newPath;
1225
+ }
1226
+ function child(path, childPath) {
1227
+ const canonicalChildPath = childPath
1228
+ .split('/')
1229
+ .filter(component => component.length > 0)
1230
+ .join('/');
1231
+ if (path.length === 0) {
1232
+ return canonicalChildPath;
1233
+ }
1234
+ else {
1235
+ return path + '/' + canonicalChildPath;
1236
+ }
1237
+ }
1238
+ /**
1239
+ * Returns the last component of a path.
1240
+ * '/foo/bar' -> 'bar'
1241
+ * '/foo/bar/baz/' -> 'baz/'
1242
+ * '/a' -> 'a'
1243
+ */
1244
+ function lastComponent(path) {
1245
+ const index = path.lastIndexOf('/', path.length - 2);
1246
+ if (index === -1) {
1247
+ return path;
1248
+ }
1249
+ else {
1250
+ return path.slice(index + 1);
1251
+ }
1252
+ }
1253
+
1254
+ /**
1255
+ * @license
1256
+ * Copyright 2017 Google LLC
1257
+ *
1258
+ * Licensed under the Apache License, Version 2.0 (the "License");
1259
+ * you may not use this file except in compliance with the License.
1260
+ * You may obtain a copy of the License at
1261
+ *
1262
+ * http://www.apache.org/licenses/LICENSE-2.0
1263
+ *
1264
+ * Unless required by applicable law or agreed to in writing, software
1265
+ * distributed under the License is distributed on an "AS IS" BASIS,
1266
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1267
+ * See the License for the specific language governing permissions and
1268
+ * limitations under the License.
1269
+ */
1270
+ function noXform_(metadata, value) {
1271
+ return value;
1272
+ }
1273
+ class Mapping {
1274
+ constructor(server, local, writable, xform) {
1275
+ this.server = server;
1276
+ this.local = local || server;
1277
+ this.writable = !!writable;
1278
+ this.xform = xform || noXform_;
1279
+ }
1280
+ }
1281
+ let mappings_ = null;
1282
+ function xformPath(fullPath) {
1283
+ if (!isString(fullPath) || fullPath.length < 2) {
1284
+ return fullPath;
1285
+ }
1286
+ else {
1287
+ return lastComponent(fullPath);
1288
+ }
1289
+ }
1290
+ function getMappings() {
1291
+ if (mappings_) {
1292
+ return mappings_;
1293
+ }
1294
+ const mappings = [];
1295
+ mappings.push(new Mapping('bucket'));
1296
+ mappings.push(new Mapping('generation'));
1297
+ mappings.push(new Mapping('metageneration'));
1298
+ mappings.push(new Mapping('name', 'fullPath', true));
1299
+ function mappingsXformPath(_metadata, fullPath) {
1300
+ return xformPath(fullPath);
1301
+ }
1302
+ const nameMapping = new Mapping('name');
1303
+ nameMapping.xform = mappingsXformPath;
1304
+ mappings.push(nameMapping);
1305
+ /**
1306
+ * Coerces the second param to a number, if it is defined.
1307
+ */
1308
+ function xformSize(_metadata, size) {
1309
+ if (size !== undefined) {
1310
+ return Number(size);
1311
+ }
1312
+ else {
1313
+ return size;
1314
+ }
1315
+ }
1316
+ const sizeMapping = new Mapping('size');
1317
+ sizeMapping.xform = xformSize;
1318
+ mappings.push(sizeMapping);
1319
+ mappings.push(new Mapping('timeCreated'));
1320
+ mappings.push(new Mapping('updated'));
1321
+ mappings.push(new Mapping('md5Hash', null, true));
1322
+ mappings.push(new Mapping('cacheControl', null, true));
1323
+ mappings.push(new Mapping('contentDisposition', null, true));
1324
+ mappings.push(new Mapping('contentEncoding', null, true));
1325
+ mappings.push(new Mapping('contentLanguage', null, true));
1326
+ mappings.push(new Mapping('contentType', null, true));
1327
+ mappings.push(new Mapping('metadata', 'customMetadata', true));
1328
+ mappings_ = mappings;
1329
+ return mappings_;
1330
+ }
1331
+ function addRef(metadata, service) {
1332
+ function generateRef() {
1333
+ const bucket = metadata['bucket'];
1334
+ const path = metadata['fullPath'];
1335
+ const loc = new Location(bucket, path);
1336
+ return service._makeStorageReference(loc);
1337
+ }
1338
+ Object.defineProperty(metadata, 'ref', { get: generateRef });
1339
+ }
1340
+ function fromResource(service, resource, mappings) {
1341
+ const metadata = {};
1342
+ metadata['type'] = 'file';
1343
+ const len = mappings.length;
1344
+ for (let i = 0; i < len; i++) {
1345
+ const mapping = mappings[i];
1346
+ metadata[mapping.local] = mapping.xform(metadata, resource[mapping.server]);
1347
+ }
1348
+ addRef(metadata, service);
1349
+ return metadata;
1350
+ }
1351
+ function fromResourceString(service, resourceString, mappings) {
1352
+ const obj = jsonObjectOrNull(resourceString);
1353
+ if (obj === null) {
1354
+ return null;
1355
+ }
1356
+ const resource = obj;
1357
+ return fromResource(service, resource, mappings);
1358
+ }
1359
+ function downloadUrlFromResourceString(metadata, resourceString, host, protocol) {
1360
+ const obj = jsonObjectOrNull(resourceString);
1361
+ if (obj === null) {
1362
+ return null;
1363
+ }
1364
+ if (!isString(obj['downloadTokens'])) {
1365
+ // This can happen if objects are uploaded through GCS and retrieved
1366
+ // through list, so we don't want to throw an Error.
1367
+ return null;
1368
+ }
1369
+ const tokens = obj['downloadTokens'];
1370
+ if (tokens.length === 0) {
1371
+ return null;
1372
+ }
1373
+ const encode = encodeURIComponent;
1374
+ const tokensList = tokens.split(',');
1375
+ const urls = tokensList.map((token) => {
1376
+ const bucket = metadata['bucket'];
1377
+ const path = metadata['fullPath'];
1378
+ const urlPart = '/b/' + encode(bucket) + '/o/' + encode(path);
1379
+ const base = makeUrl(urlPart, host, protocol);
1380
+ const queryString = makeQueryString({
1381
+ alt: 'media',
1382
+ token
1383
+ });
1384
+ return base + queryString;
1385
+ });
1386
+ return urls[0];
1387
+ }
1388
+ function toResourceString(metadata, mappings) {
1389
+ const resource = {};
1390
+ const len = mappings.length;
1391
+ for (let i = 0; i < len; i++) {
1392
+ const mapping = mappings[i];
1393
+ if (mapping.writable) {
1394
+ resource[mapping.server] = metadata[mapping.local];
1395
+ }
1396
+ }
1397
+ return JSON.stringify(resource);
1398
+ }
1399
+
1400
+ /**
1401
+ * @license
1402
+ * Copyright 2019 Google LLC
1403
+ *
1404
+ * Licensed under the Apache License, Version 2.0 (the "License");
1405
+ * you may not use this file except in compliance with the License.
1406
+ * You may obtain a copy of the License at
1407
+ *
1408
+ * http://www.apache.org/licenses/LICENSE-2.0
1409
+ *
1410
+ * Unless required by applicable law or agreed to in writing, software
1411
+ * distributed under the License is distributed on an "AS IS" BASIS,
1412
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1413
+ * See the License for the specific language governing permissions and
1414
+ * limitations under the License.
1415
+ */
1416
+ const PREFIXES_KEY = 'prefixes';
1417
+ const ITEMS_KEY = 'items';
1418
+ function fromBackendResponse(service, bucket, resource) {
1419
+ const listResult = {
1420
+ prefixes: [],
1421
+ items: [],
1422
+ nextPageToken: resource['nextPageToken']
1423
+ };
1424
+ if (resource[PREFIXES_KEY]) {
1425
+ for (const path of resource[PREFIXES_KEY]) {
1426
+ const pathWithoutTrailingSlash = path.replace(/\/$/, '');
1427
+ const reference = service._makeStorageReference(new Location(bucket, pathWithoutTrailingSlash));
1428
+ listResult.prefixes.push(reference);
1429
+ }
1430
+ }
1431
+ if (resource[ITEMS_KEY]) {
1432
+ for (const item of resource[ITEMS_KEY]) {
1433
+ const reference = service._makeStorageReference(new Location(bucket, item['name']));
1434
+ listResult.items.push(reference);
1435
+ }
1436
+ }
1437
+ return listResult;
1438
+ }
1439
+ function fromResponseString(service, bucket, resourceString) {
1440
+ const obj = jsonObjectOrNull(resourceString);
1441
+ if (obj === null) {
1442
+ return null;
1443
+ }
1444
+ const resource = obj;
1445
+ return fromBackendResponse(service, bucket, resource);
1446
+ }
1447
+
1448
+ class RequestInfo {
1449
+ constructor(url, method,
1450
+ /**
1451
+ * Returns the value with which to resolve the request's promise. Only called
1452
+ * if the request is successful. Throw from this function to reject the
1453
+ * returned Request's promise with the thrown error.
1454
+ * Note: The XhrIo passed to this function may be reused after this callback
1455
+ * returns. Do not keep a reference to it in any way.
1456
+ */
1457
+ handler, timeout) {
1458
+ this.url = url;
1459
+ this.method = method;
1460
+ this.handler = handler;
1461
+ this.timeout = timeout;
1462
+ this.urlParams = {};
1463
+ this.headers = {};
1464
+ this.body = null;
1465
+ this.errorHandler = null;
1466
+ /**
1467
+ * Called with the current number of bytes uploaded and total size (-1 if not
1468
+ * computable) of the request body (i.e. used to report upload progress).
1469
+ */
1470
+ this.progressCallback = null;
1471
+ this.successCodes = [200];
1472
+ this.additionalRetryCodes = [];
1473
+ }
1474
+ }
1475
+
1476
+ /**
1477
+ * @license
1478
+ * Copyright 2017 Google LLC
1479
+ *
1480
+ * Licensed under the Apache License, Version 2.0 (the "License");
1481
+ * you may not use this file except in compliance with the License.
1482
+ * You may obtain a copy of the License at
1483
+ *
1484
+ * http://www.apache.org/licenses/LICENSE-2.0
1485
+ *
1486
+ * Unless required by applicable law or agreed to in writing, software
1487
+ * distributed under the License is distributed on an "AS IS" BASIS,
1488
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1489
+ * See the License for the specific language governing permissions and
1490
+ * limitations under the License.
1491
+ */
1492
+ /**
1493
+ * Throws the UNKNOWN StorageError if cndn is false.
1494
+ */
1495
+ function handlerCheck(cndn) {
1496
+ if (!cndn) {
1497
+ throw unknown();
1498
+ }
1499
+ }
1500
+ function metadataHandler(service, mappings) {
1501
+ function handler(xhr, text) {
1502
+ const metadata = fromResourceString(service, text, mappings);
1503
+ handlerCheck(metadata !== null);
1504
+ return metadata;
1505
+ }
1506
+ return handler;
1507
+ }
1508
+ function listHandler(service, bucket) {
1509
+ function handler(xhr, text) {
1510
+ const listResult = fromResponseString(service, bucket, text);
1511
+ handlerCheck(listResult !== null);
1512
+ return listResult;
1513
+ }
1514
+ return handler;
1515
+ }
1516
+ function downloadUrlHandler(service, mappings) {
1517
+ function handler(xhr, text) {
1518
+ const metadata = fromResourceString(service, text, mappings);
1519
+ handlerCheck(metadata !== null);
1520
+ return downloadUrlFromResourceString(metadata, text, service.host, service._protocol);
1521
+ }
1522
+ return handler;
1523
+ }
1524
+ function sharedErrorHandler(location) {
1525
+ function errorHandler(xhr, err) {
1526
+ let newErr;
1527
+ if (xhr.getStatus() === 401) {
1528
+ if (
1529
+ // This exact message string is the only consistent part of the
1530
+ // server's error response that identifies it as an App Check error.
1531
+ xhr.getResponseText().includes('Firebase App Check token is invalid')) {
1532
+ newErr = unauthorizedApp();
1533
+ }
1534
+ else {
1535
+ newErr = unauthenticated();
1536
+ }
1537
+ }
1538
+ else {
1539
+ if (xhr.getStatus() === 402) {
1540
+ newErr = quotaExceeded(location.bucket);
1541
+ }
1542
+ else {
1543
+ if (xhr.getStatus() === 403) {
1544
+ newErr = unauthorized(location.path);
1545
+ }
1546
+ else {
1547
+ newErr = err;
1548
+ }
1549
+ }
1550
+ }
1551
+ newErr.serverResponse = err.serverResponse;
1552
+ return newErr;
1553
+ }
1554
+ return errorHandler;
1555
+ }
1556
+ function objectErrorHandler(location) {
1557
+ const shared = sharedErrorHandler(location);
1558
+ function errorHandler(xhr, err) {
1559
+ let newErr = shared(xhr, err);
1560
+ if (xhr.getStatus() === 404) {
1561
+ newErr = objectNotFound(location.path);
1562
+ }
1563
+ newErr.serverResponse = err.serverResponse;
1564
+ return newErr;
1565
+ }
1566
+ return errorHandler;
1567
+ }
1568
+ function getMetadata$2(service, location, mappings) {
1569
+ const urlPart = location.fullServerUrl();
1570
+ const url = makeUrl(urlPart, service.host, service._protocol);
1571
+ const method = 'GET';
1572
+ const timeout = service.maxOperationRetryTime;
1573
+ const requestInfo = new RequestInfo(url, method, metadataHandler(service, mappings), timeout);
1574
+ requestInfo.errorHandler = objectErrorHandler(location);
1575
+ return requestInfo;
1576
+ }
1577
+ function list$2(service, location, delimiter, pageToken, maxResults) {
1578
+ const urlParams = {};
1579
+ if (location.isRoot) {
1580
+ urlParams['prefix'] = '';
1581
+ }
1582
+ else {
1583
+ urlParams['prefix'] = location.path + '/';
1584
+ }
1585
+ if (delimiter && delimiter.length > 0) {
1586
+ urlParams['delimiter'] = delimiter;
1587
+ }
1588
+ if (pageToken) {
1589
+ urlParams['pageToken'] = pageToken;
1590
+ }
1591
+ if (maxResults) {
1592
+ urlParams['maxResults'] = maxResults;
1593
+ }
1594
+ const urlPart = location.bucketOnlyServerUrl();
1595
+ const url = makeUrl(urlPart, service.host, service._protocol);
1596
+ const method = 'GET';
1597
+ const timeout = service.maxOperationRetryTime;
1598
+ const requestInfo = new RequestInfo(url, method, listHandler(service, location.bucket), timeout);
1599
+ requestInfo.urlParams = urlParams;
1600
+ requestInfo.errorHandler = sharedErrorHandler(location);
1601
+ return requestInfo;
1602
+ }
1603
+ function getDownloadUrl(service, location, mappings) {
1604
+ const urlPart = location.fullServerUrl();
1605
+ const url = makeUrl(urlPart, service.host, service._protocol);
1606
+ const method = 'GET';
1607
+ const timeout = service.maxOperationRetryTime;
1608
+ const requestInfo = new RequestInfo(url, method, downloadUrlHandler(service, mappings), timeout);
1609
+ requestInfo.errorHandler = objectErrorHandler(location);
1610
+ return requestInfo;
1611
+ }
1612
+ function updateMetadata$2(service, location, metadata, mappings) {
1613
+ const urlPart = location.fullServerUrl();
1614
+ const url = makeUrl(urlPart, service.host, service._protocol);
1615
+ const method = 'PATCH';
1616
+ const body = toResourceString(metadata, mappings);
1617
+ const headers = { 'Content-Type': 'application/json; charset=utf-8' };
1618
+ const timeout = service.maxOperationRetryTime;
1619
+ const requestInfo = new RequestInfo(url, method, metadataHandler(service, mappings), timeout);
1620
+ requestInfo.headers = headers;
1621
+ requestInfo.body = body;
1622
+ requestInfo.errorHandler = objectErrorHandler(location);
1623
+ return requestInfo;
1624
+ }
1625
+ function deleteObject$2(service, location) {
1626
+ const urlPart = location.fullServerUrl();
1627
+ const url = makeUrl(urlPart, service.host, service._protocol);
1628
+ const method = 'DELETE';
1629
+ const timeout = service.maxOperationRetryTime;
1630
+ function handler(_xhr, _text) { }
1631
+ const requestInfo = new RequestInfo(url, method, handler, timeout);
1632
+ requestInfo.successCodes = [200, 204];
1633
+ requestInfo.errorHandler = objectErrorHandler(location);
1634
+ return requestInfo;
1635
+ }
1636
+ function determineContentType_(metadata, blob) {
1637
+ return ((metadata && metadata['contentType']) ||
1638
+ (blob && blob.type()) ||
1639
+ 'application/octet-stream');
1640
+ }
1641
+ function metadataForUpload_(location, blob, metadata) {
1642
+ const metadataClone = Object.assign({}, metadata);
1643
+ metadataClone['fullPath'] = location.path;
1644
+ metadataClone['size'] = blob.size();
1645
+ if (!metadataClone['contentType']) {
1646
+ metadataClone['contentType'] = determineContentType_(null, blob);
1647
+ }
1648
+ return metadataClone;
1649
+ }
1650
+ /**
1651
+ * Prepare RequestInfo for uploads as Content-Type: multipart.
1652
+ */
1653
+ function multipartUpload(service, location, mappings, blob, metadata) {
1654
+ const urlPart = location.bucketOnlyServerUrl();
1655
+ const headers = {
1656
+ 'X-Goog-Upload-Protocol': 'multipart'
1657
+ };
1658
+ function genBoundary() {
1659
+ let str = '';
1660
+ for (let i = 0; i < 2; i++) {
1661
+ str = str + Math.random().toString().slice(2);
1662
+ }
1663
+ return str;
1664
+ }
1665
+ const boundary = genBoundary();
1666
+ headers['Content-Type'] = 'multipart/related; boundary=' + boundary;
1667
+ const metadata_ = metadataForUpload_(location, blob, metadata);
1668
+ const metadataString = toResourceString(metadata_, mappings);
1669
+ const preBlobPart = '--' +
1670
+ boundary +
1671
+ '\r\n' +
1672
+ 'Content-Type: application/json; charset=utf-8\r\n\r\n' +
1673
+ metadataString +
1674
+ '\r\n--' +
1675
+ boundary +
1676
+ '\r\n' +
1677
+ 'Content-Type: ' +
1678
+ metadata_['contentType'] +
1679
+ '\r\n\r\n';
1680
+ const postBlobPart = '\r\n--' + boundary + '--';
1681
+ const body = FbsBlob.getBlob(preBlobPart, blob, postBlobPart);
1682
+ if (body === null) {
1683
+ throw cannotSliceBlob();
1684
+ }
1685
+ const urlParams = { name: metadata_['fullPath'] };
1686
+ const url = makeUrl(urlPart, service.host, service._protocol);
1687
+ const method = 'POST';
1688
+ const timeout = service.maxUploadRetryTime;
1689
+ const requestInfo = new RequestInfo(url, method, metadataHandler(service, mappings), timeout);
1690
+ requestInfo.urlParams = urlParams;
1691
+ requestInfo.headers = headers;
1692
+ requestInfo.body = body.uploadData();
1693
+ requestInfo.errorHandler = sharedErrorHandler(location);
1694
+ return requestInfo;
1695
+ }
1696
+ /**
1697
+ * @param current The number of bytes that have been uploaded so far.
1698
+ * @param total The total number of bytes in the upload.
1699
+ * @param opt_finalized True if the server has finished the upload.
1700
+ * @param opt_metadata The upload metadata, should
1701
+ * only be passed if opt_finalized is true.
1702
+ */
1703
+ class ResumableUploadStatus {
1704
+ constructor(current, total, finalized, metadata) {
1705
+ this.current = current;
1706
+ this.total = total;
1707
+ this.finalized = !!finalized;
1708
+ this.metadata = metadata || null;
1709
+ }
1710
+ }
1711
+ function checkResumeHeader_(xhr, allowed) {
1712
+ let status = null;
1713
+ try {
1714
+ status = xhr.getResponseHeader('X-Goog-Upload-Status');
1715
+ }
1716
+ catch (e) {
1717
+ handlerCheck(false);
1718
+ }
1719
+ const allowedStatus = allowed || ['active'];
1720
+ handlerCheck(!!status && allowedStatus.indexOf(status) !== -1);
1721
+ return status;
1722
+ }
1723
+ function createResumableUpload(service, location, mappings, blob, metadata) {
1724
+ const urlPart = location.bucketOnlyServerUrl();
1725
+ const metadataForUpload = metadataForUpload_(location, blob, metadata);
1726
+ const urlParams = { name: metadataForUpload['fullPath'] };
1727
+ const url = makeUrl(urlPart, service.host, service._protocol);
1728
+ const method = 'POST';
1729
+ const headers = {
1730
+ 'X-Goog-Upload-Protocol': 'resumable',
1731
+ 'X-Goog-Upload-Command': 'start',
1732
+ 'X-Goog-Upload-Header-Content-Length': `${blob.size()}`,
1733
+ 'X-Goog-Upload-Header-Content-Type': metadataForUpload['contentType'],
1734
+ 'Content-Type': 'application/json; charset=utf-8'
1735
+ };
1736
+ const body = toResourceString(metadataForUpload, mappings);
1737
+ const timeout = service.maxUploadRetryTime;
1738
+ function handler(xhr) {
1739
+ checkResumeHeader_(xhr);
1740
+ let url;
1741
+ try {
1742
+ url = xhr.getResponseHeader('X-Goog-Upload-URL');
1743
+ }
1744
+ catch (e) {
1745
+ handlerCheck(false);
1746
+ }
1747
+ handlerCheck(isString(url));
1748
+ return url;
1749
+ }
1750
+ const requestInfo = new RequestInfo(url, method, handler, timeout);
1751
+ requestInfo.urlParams = urlParams;
1752
+ requestInfo.headers = headers;
1753
+ requestInfo.body = body;
1754
+ requestInfo.errorHandler = sharedErrorHandler(location);
1755
+ return requestInfo;
1756
+ }
1757
+ /**
1758
+ * @param url From a call to fbs.requests.createResumableUpload.
1759
+ */
1760
+ function getResumableUploadStatus(service, location, url, blob) {
1761
+ const headers = { 'X-Goog-Upload-Command': 'query' };
1762
+ function handler(xhr) {
1763
+ const status = checkResumeHeader_(xhr, ['active', 'final']);
1764
+ let sizeString = null;
1765
+ try {
1766
+ sizeString = xhr.getResponseHeader('X-Goog-Upload-Size-Received');
1767
+ }
1768
+ catch (e) {
1769
+ handlerCheck(false);
1770
+ }
1771
+ if (!sizeString) {
1772
+ // null or empty string
1773
+ handlerCheck(false);
1774
+ }
1775
+ const size = Number(sizeString);
1776
+ handlerCheck(!isNaN(size));
1777
+ return new ResumableUploadStatus(size, blob.size(), status === 'final');
1778
+ }
1779
+ const method = 'POST';
1780
+ const timeout = service.maxUploadRetryTime;
1781
+ const requestInfo = new RequestInfo(url, method, handler, timeout);
1782
+ requestInfo.headers = headers;
1783
+ requestInfo.errorHandler = sharedErrorHandler(location);
1784
+ return requestInfo;
1785
+ }
1786
+ /**
1787
+ * Any uploads via the resumable upload API must transfer a number of bytes
1788
+ * that is a multiple of this number.
1789
+ */
1790
+ const RESUMABLE_UPLOAD_CHUNK_SIZE = 256 * 1024;
1791
+ /**
1792
+ * @param url From a call to fbs.requests.createResumableUpload.
1793
+ * @param chunkSize Number of bytes to upload.
1794
+ * @param status The previous status.
1795
+ * If not passed or null, we start from the beginning.
1796
+ * @throws fbs.Error If the upload is already complete, the passed in status
1797
+ * has a final size inconsistent with the blob, or the blob cannot be sliced
1798
+ * for upload.
1799
+ */
1800
+ function continueResumableUpload(location, service, url, blob, chunkSize, mappings, status, progressCallback) {
1801
+ // TODO(andysoto): standardize on internal asserts
1802
+ // assert(!(opt_status && opt_status.finalized));
1803
+ const status_ = new ResumableUploadStatus(0, 0);
1804
+ if (status) {
1805
+ status_.current = status.current;
1806
+ status_.total = status.total;
1807
+ }
1808
+ else {
1809
+ status_.current = 0;
1810
+ status_.total = blob.size();
1811
+ }
1812
+ if (blob.size() !== status_.total) {
1813
+ throw serverFileWrongSize();
1814
+ }
1815
+ const bytesLeft = status_.total - status_.current;
1816
+ let bytesToUpload = bytesLeft;
1817
+ if (chunkSize > 0) {
1818
+ bytesToUpload = Math.min(bytesToUpload, chunkSize);
1819
+ }
1820
+ const startByte = status_.current;
1821
+ const endByte = startByte + bytesToUpload;
1822
+ const uploadCommand = bytesToUpload === bytesLeft ? 'upload, finalize' : 'upload';
1823
+ const headers = {
1824
+ 'X-Goog-Upload-Command': uploadCommand,
1825
+ 'X-Goog-Upload-Offset': `${status_.current}`
1826
+ };
1827
+ const body = blob.slice(startByte, endByte);
1828
+ if (body === null) {
1829
+ throw cannotSliceBlob();
1830
+ }
1831
+ function handler(xhr, text) {
1832
+ // TODO(andysoto): Verify the MD5 of each uploaded range:
1833
+ // the 'x-range-md5' header comes back with status code 308 responses.
1834
+ // We'll only be able to bail out though, because you can't re-upload a
1835
+ // range that you previously uploaded.
1836
+ const uploadStatus = checkResumeHeader_(xhr, ['active', 'final']);
1837
+ const newCurrent = status_.current + bytesToUpload;
1838
+ const size = blob.size();
1839
+ let metadata;
1840
+ if (uploadStatus === 'final') {
1841
+ metadata = metadataHandler(service, mappings)(xhr, text);
1842
+ }
1843
+ else {
1844
+ metadata = null;
1845
+ }
1846
+ return new ResumableUploadStatus(newCurrent, size, uploadStatus === 'final', metadata);
1847
+ }
1848
+ const method = 'POST';
1849
+ const timeout = service.maxUploadRetryTime;
1850
+ const requestInfo = new RequestInfo(url, method, handler, timeout);
1851
+ requestInfo.headers = headers;
1852
+ requestInfo.body = body.uploadData();
1853
+ requestInfo.progressCallback = progressCallback || null;
1854
+ requestInfo.errorHandler = sharedErrorHandler(location);
1855
+ return requestInfo;
1856
+ }
1857
+
1858
+ /**
1859
+ * @license
1860
+ * Copyright 2017 Google LLC
1861
+ *
1862
+ * Licensed under the Apache License, Version 2.0 (the "License");
1863
+ * you may not use this file except in compliance with the License.
1864
+ * You may obtain a copy of the License at
1865
+ *
1866
+ * http://www.apache.org/licenses/LICENSE-2.0
1867
+ *
1868
+ * Unless required by applicable law or agreed to in writing, software
1869
+ * distributed under the License is distributed on an "AS IS" BASIS,
1870
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1871
+ * See the License for the specific language governing permissions and
1872
+ * limitations under the License.
1873
+ */
1874
+ /**
1875
+ * An event that is triggered on a task.
1876
+ * @internal
1877
+ */
1878
+ const TaskEvent = {
1879
+ /**
1880
+ * For this event,
1881
+ * <ul>
1882
+ * <li>The `next` function is triggered on progress updates and when the
1883
+ * task is paused/resumed with an `UploadTaskSnapshot` as the first
1884
+ * argument.</li>
1885
+ * <li>The `error` function is triggered if the upload is canceled or fails
1886
+ * for another reason.</li>
1887
+ * <li>The `complete` function is triggered if the upload completes
1888
+ * successfully.</li>
1889
+ * </ul>
1890
+ */
1891
+ STATE_CHANGED: 'state_changed'
1892
+ };
1893
+ // type keys = keyof TaskState
1894
+ /**
1895
+ * Represents the current state of a running upload.
1896
+ * @internal
1897
+ */
1898
+ const TaskState = {
1899
+ /** The task is currently transferring data. */
1900
+ RUNNING: 'running',
1901
+ /** The task was paused by the user. */
1902
+ PAUSED: 'paused',
1903
+ /** The task completed successfully. */
1904
+ SUCCESS: 'success',
1905
+ /** The task was canceled. */
1906
+ CANCELED: 'canceled',
1907
+ /** The task failed with an error. */
1908
+ ERROR: 'error'
1909
+ };
1910
+ function taskStateFromInternalTaskState(state) {
1911
+ switch (state) {
1912
+ case "running" /* RUNNING */:
1913
+ case "pausing" /* PAUSING */:
1914
+ case "canceling" /* CANCELING */:
1915
+ return TaskState.RUNNING;
1916
+ case "paused" /* PAUSED */:
1917
+ return TaskState.PAUSED;
1918
+ case "success" /* SUCCESS */:
1919
+ return TaskState.SUCCESS;
1920
+ case "canceled" /* CANCELED */:
1921
+ return TaskState.CANCELED;
1922
+ case "error" /* ERROR */:
1923
+ return TaskState.ERROR;
1924
+ default:
1925
+ // TODO(andysoto): assert(false);
1926
+ return TaskState.ERROR;
1927
+ }
1928
+ }
1929
+
1930
+ /**
1931
+ * @license
1932
+ * Copyright 2017 Google LLC
1933
+ *
1934
+ * Licensed under the Apache License, Version 2.0 (the "License");
1935
+ * you may not use this file except in compliance with the License.
1936
+ * You may obtain a copy of the License at
1937
+ *
1938
+ * http://www.apache.org/licenses/LICENSE-2.0
1939
+ *
1940
+ * Unless required by applicable law or agreed to in writing, software
1941
+ * distributed under the License is distributed on an "AS IS" BASIS,
1942
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1943
+ * See the License for the specific language governing permissions and
1944
+ * limitations under the License.
1945
+ */
1946
+ class Observer {
1947
+ constructor(nextOrObserver, error, complete) {
1948
+ const asFunctions = isFunction(nextOrObserver) || error != null || complete != null;
1949
+ if (asFunctions) {
1950
+ this.next = nextOrObserver;
1951
+ this.error = error !== null && error !== void 0 ? error : undefined;
1952
+ this.complete = complete !== null && complete !== void 0 ? complete : undefined;
1953
+ }
1954
+ else {
1955
+ const observer = nextOrObserver;
1956
+ this.next = observer.next;
1957
+ this.error = observer.error;
1958
+ this.complete = observer.complete;
1959
+ }
1960
+ }
1961
+ }
1962
+
1963
+ /**
1964
+ * @license
1965
+ * Copyright 2017 Google LLC
1966
+ *
1967
+ * Licensed under the Apache License, Version 2.0 (the "License");
1968
+ * you may not use this file except in compliance with the License.
1969
+ * You may obtain a copy of the License at
1970
+ *
1971
+ * http://www.apache.org/licenses/LICENSE-2.0
1972
+ *
1973
+ * Unless required by applicable law or agreed to in writing, software
1974
+ * distributed under the License is distributed on an "AS IS" BASIS,
1975
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1976
+ * See the License for the specific language governing permissions and
1977
+ * limitations under the License.
1978
+ */
1979
+ /**
1980
+ * Returns a function that invokes f with its arguments asynchronously as a
1981
+ * microtask, i.e. as soon as possible after the current script returns back
1982
+ * into browser code.
1983
+ */
1984
+ // eslint-disable-next-line @typescript-eslint/ban-types
1985
+ function async(f) {
1986
+ return (...argsToForward) => {
1987
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
1988
+ Promise.resolve().then(() => f(...argsToForward));
1989
+ };
1990
+ }
1991
+
1992
+ /**
1993
+ * @license
1994
+ * Copyright 2021 Google LLC
1995
+ *
1996
+ * Licensed under the Apache License, Version 2.0 (the "License");
1997
+ * you may not use this file except in compliance with the License.
1998
+ * You may obtain a copy of the License at
1999
+ *
2000
+ * http://www.apache.org/licenses/LICENSE-2.0
2001
+ *
2002
+ * Unless required by applicable law or agreed to in writing, software
2003
+ * distributed under the License is distributed on an "AS IS" BASIS,
2004
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2005
+ * See the License for the specific language governing permissions and
2006
+ * limitations under the License.
2007
+ */
2008
+ /** An override for the text-based Connection. Used in tests. */
2009
+ let connectionFactoryOverride = null;
2010
+ /**
2011
+ * Network layer that works in Node.
2012
+ *
2013
+ * This network implementation should not be used in browsers as it does not
2014
+ * support progress updates.
2015
+ */
2016
+ class FetchConnection {
2017
+ constructor() {
2018
+ this.sent_ = false;
2019
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2020
+ this.fetch_ = nodeFetch;
2021
+ this.errorCode_ = ErrorCode.NO_ERROR;
2022
+ }
2023
+ send(url, method, body, headers) {
2024
+ if (this.sent_) {
2025
+ throw internalError('cannot .send() more than once');
2026
+ }
2027
+ this.sent_ = true;
2028
+ return this.fetch_(url, {
2029
+ method,
2030
+ headers: headers || {},
2031
+ body
2032
+ }).then(resp => {
2033
+ this.headers_ = resp.headers;
2034
+ this.statusCode_ = resp.status;
2035
+ return resp.text().then(body => {
2036
+ this.body_ = body;
2037
+ });
2038
+ }, (_err) => {
2039
+ this.errorCode_ = ErrorCode.NETWORK_ERROR;
2040
+ // emulate XHR which sets status to 0 when encountering a network error
2041
+ this.statusCode_ = 0;
2042
+ });
2043
+ }
2044
+ getErrorCode() {
2045
+ if (this.errorCode_ === undefined) {
2046
+ throw internalError('cannot .getErrorCode() before receiving response');
2047
+ }
2048
+ return this.errorCode_;
2049
+ }
2050
+ getStatus() {
2051
+ if (this.statusCode_ === undefined) {
2052
+ throw internalError('cannot .getStatus() before receiving response');
2053
+ }
2054
+ return this.statusCode_;
2055
+ }
2056
+ getResponseText() {
2057
+ if (this.body_ === undefined) {
2058
+ throw internalError('cannot .getResponseText() before receiving response');
2059
+ }
2060
+ return this.body_;
2061
+ }
2062
+ abort() {
2063
+ // Not supported
2064
+ }
2065
+ getResponseHeader(header) {
2066
+ if (!this.headers_) {
2067
+ throw internalError('cannot .getResponseText() before receiving response');
2068
+ }
2069
+ return this.headers_.get(header);
2070
+ }
2071
+ addUploadProgressListener(listener) {
2072
+ // Not supported
2073
+ }
2074
+ /**
2075
+ * @override
2076
+ */
2077
+ removeUploadProgressListener(listener) {
2078
+ // Not supported
2079
+ }
2080
+ }
2081
+ function newConnection() {
2082
+ return connectionFactoryOverride
2083
+ ? connectionFactoryOverride()
2084
+ : new FetchConnection();
2085
+ }
2086
+
2087
+ /**
2088
+ * @license
2089
+ * Copyright 2017 Google LLC
2090
+ *
2091
+ * Licensed under the Apache License, Version 2.0 (the "License");
2092
+ * you may not use this file except in compliance with the License.
2093
+ * You may obtain a copy of the License at
2094
+ *
2095
+ * http://www.apache.org/licenses/LICENSE-2.0
2096
+ *
2097
+ * Unless required by applicable law or agreed to in writing, software
2098
+ * distributed under the License is distributed on an "AS IS" BASIS,
2099
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2100
+ * See the License for the specific language governing permissions and
2101
+ * limitations under the License.
2102
+ */
2103
+ /**
2104
+ * Represents a blob being uploaded. Can be used to pause/resume/cancel the
2105
+ * upload and manage callbacks for various events.
2106
+ * @internal
2107
+ */
2108
+ class UploadTask {
2109
+ /**
2110
+ * @param ref - The firebaseStorage.Reference object this task came
2111
+ * from, untyped to avoid cyclic dependencies.
2112
+ * @param blob - The blob to upload.
2113
+ */
2114
+ constructor(ref, blob, metadata = null) {
2115
+ /**
2116
+ * Number of bytes transferred so far.
2117
+ */
2118
+ this._transferred = 0;
2119
+ this._needToFetchStatus = false;
2120
+ this._needToFetchMetadata = false;
2121
+ this._observers = [];
2122
+ this._error = undefined;
2123
+ this._uploadUrl = undefined;
2124
+ this._request = undefined;
2125
+ this._chunkMultiplier = 1;
2126
+ this._resolve = undefined;
2127
+ this._reject = undefined;
2128
+ this._ref = ref;
2129
+ this._blob = blob;
2130
+ this._metadata = metadata;
2131
+ this._mappings = getMappings();
2132
+ this._resumable = this._shouldDoResumable(this._blob);
2133
+ this._state = "running" /* RUNNING */;
2134
+ this._errorHandler = error => {
2135
+ this._request = undefined;
2136
+ this._chunkMultiplier = 1;
2137
+ if (error._codeEquals("canceled" /* CANCELED */)) {
2138
+ this._needToFetchStatus = true;
2139
+ this.completeTransitions_();
2140
+ }
2141
+ else {
2142
+ this._error = error;
2143
+ this._transition("error" /* ERROR */);
2144
+ }
2145
+ };
2146
+ this._metadataErrorHandler = error => {
2147
+ this._request = undefined;
2148
+ if (error._codeEquals("canceled" /* CANCELED */)) {
2149
+ this.completeTransitions_();
2150
+ }
2151
+ else {
2152
+ this._error = error;
2153
+ this._transition("error" /* ERROR */);
2154
+ }
2155
+ };
2156
+ this._promise = new Promise((resolve, reject) => {
2157
+ this._resolve = resolve;
2158
+ this._reject = reject;
2159
+ this._start();
2160
+ });
2161
+ // Prevent uncaught rejections on the internal promise from bubbling out
2162
+ // to the top level with a dummy handler.
2163
+ this._promise.then(null, () => { });
2164
+ }
2165
+ _makeProgressCallback() {
2166
+ const sizeBefore = this._transferred;
2167
+ return loaded => this._updateProgress(sizeBefore + loaded);
2168
+ }
2169
+ _shouldDoResumable(blob) {
2170
+ return blob.size() > 256 * 1024;
2171
+ }
2172
+ _start() {
2173
+ if (this._state !== "running" /* RUNNING */) {
2174
+ // This can happen if someone pauses us in a resume callback, for example.
2175
+ return;
2176
+ }
2177
+ if (this._request !== undefined) {
2178
+ return;
2179
+ }
2180
+ if (this._resumable) {
2181
+ if (this._uploadUrl === undefined) {
2182
+ this._createResumable();
2183
+ }
2184
+ else {
2185
+ if (this._needToFetchStatus) {
2186
+ this._fetchStatus();
2187
+ }
2188
+ else {
2189
+ if (this._needToFetchMetadata) {
2190
+ // Happens if we miss the metadata on upload completion.
2191
+ this._fetchMetadata();
2192
+ }
2193
+ else {
2194
+ this._continueUpload();
2195
+ }
2196
+ }
2197
+ }
2198
+ }
2199
+ else {
2200
+ this._oneShotUpload();
2201
+ }
2202
+ }
2203
+ _resolveToken(callback) {
2204
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
2205
+ Promise.all([
2206
+ this._ref.storage._getAuthToken(),
2207
+ this._ref.storage._getAppCheckToken()
2208
+ ]).then(([authToken, appCheckToken]) => {
2209
+ switch (this._state) {
2210
+ case "running" /* RUNNING */:
2211
+ callback(authToken, appCheckToken);
2212
+ break;
2213
+ case "canceling" /* CANCELING */:
2214
+ this._transition("canceled" /* CANCELED */);
2215
+ break;
2216
+ case "pausing" /* PAUSING */:
2217
+ this._transition("paused" /* PAUSED */);
2218
+ break;
2219
+ }
2220
+ });
2221
+ }
2222
+ // TODO(andysoto): assert false
2223
+ _createResumable() {
2224
+ this._resolveToken((authToken, appCheckToken) => {
2225
+ const requestInfo = createResumableUpload(this._ref.storage, this._ref._location, this._mappings, this._blob, this._metadata);
2226
+ const createRequest = this._ref.storage._makeRequest(requestInfo, newConnection, authToken, appCheckToken);
2227
+ this._request = createRequest;
2228
+ createRequest.getPromise().then((url) => {
2229
+ this._request = undefined;
2230
+ this._uploadUrl = url;
2231
+ this._needToFetchStatus = false;
2232
+ this.completeTransitions_();
2233
+ }, this._errorHandler);
2234
+ });
2235
+ }
2236
+ _fetchStatus() {
2237
+ // TODO(andysoto): assert(this.uploadUrl_ !== null);
2238
+ const url = this._uploadUrl;
2239
+ this._resolveToken((authToken, appCheckToken) => {
2240
+ const requestInfo = getResumableUploadStatus(this._ref.storage, this._ref._location, url, this._blob);
2241
+ const statusRequest = this._ref.storage._makeRequest(requestInfo, newConnection, authToken, appCheckToken);
2242
+ this._request = statusRequest;
2243
+ statusRequest.getPromise().then(status => {
2244
+ status = status;
2245
+ this._request = undefined;
2246
+ this._updateProgress(status.current);
2247
+ this._needToFetchStatus = false;
2248
+ if (status.finalized) {
2249
+ this._needToFetchMetadata = true;
2250
+ }
2251
+ this.completeTransitions_();
2252
+ }, this._errorHandler);
2253
+ });
2254
+ }
2255
+ _continueUpload() {
2256
+ const chunkSize = RESUMABLE_UPLOAD_CHUNK_SIZE * this._chunkMultiplier;
2257
+ const status = new ResumableUploadStatus(this._transferred, this._blob.size());
2258
+ // TODO(andysoto): assert(this.uploadUrl_ !== null);
2259
+ const url = this._uploadUrl;
2260
+ this._resolveToken((authToken, appCheckToken) => {
2261
+ let requestInfo;
2262
+ try {
2263
+ requestInfo = continueResumableUpload(this._ref._location, this._ref.storage, url, this._blob, chunkSize, this._mappings, status, this._makeProgressCallback());
2264
+ }
2265
+ catch (e) {
2266
+ this._error = e;
2267
+ this._transition("error" /* ERROR */);
2268
+ return;
2269
+ }
2270
+ const uploadRequest = this._ref.storage._makeRequest(requestInfo, newConnection, authToken, appCheckToken);
2271
+ this._request = uploadRequest;
2272
+ uploadRequest.getPromise().then((newStatus) => {
2273
+ this._increaseMultiplier();
2274
+ this._request = undefined;
2275
+ this._updateProgress(newStatus.current);
2276
+ if (newStatus.finalized) {
2277
+ this._metadata = newStatus.metadata;
2278
+ this._transition("success" /* SUCCESS */);
2279
+ }
2280
+ else {
2281
+ this.completeTransitions_();
2282
+ }
2283
+ }, this._errorHandler);
2284
+ });
2285
+ }
2286
+ _increaseMultiplier() {
2287
+ const currentSize = RESUMABLE_UPLOAD_CHUNK_SIZE * this._chunkMultiplier;
2288
+ // Max chunk size is 32M.
2289
+ if (currentSize < 32 * 1024 * 1024) {
2290
+ this._chunkMultiplier *= 2;
2291
+ }
2292
+ }
2293
+ _fetchMetadata() {
2294
+ this._resolveToken((authToken, appCheckToken) => {
2295
+ const requestInfo = getMetadata$2(this._ref.storage, this._ref._location, this._mappings);
2296
+ const metadataRequest = this._ref.storage._makeRequest(requestInfo, newConnection, authToken, appCheckToken);
2297
+ this._request = metadataRequest;
2298
+ metadataRequest.getPromise().then(metadata => {
2299
+ this._request = undefined;
2300
+ this._metadata = metadata;
2301
+ this._transition("success" /* SUCCESS */);
2302
+ }, this._metadataErrorHandler);
2303
+ });
2304
+ }
2305
+ _oneShotUpload() {
2306
+ this._resolveToken((authToken, appCheckToken) => {
2307
+ const requestInfo = multipartUpload(this._ref.storage, this._ref._location, this._mappings, this._blob, this._metadata);
2308
+ const multipartRequest = this._ref.storage._makeRequest(requestInfo, newConnection, authToken, appCheckToken);
2309
+ this._request = multipartRequest;
2310
+ multipartRequest.getPromise().then(metadata => {
2311
+ this._request = undefined;
2312
+ this._metadata = metadata;
2313
+ this._updateProgress(this._blob.size());
2314
+ this._transition("success" /* SUCCESS */);
2315
+ }, this._errorHandler);
2316
+ });
2317
+ }
2318
+ _updateProgress(transferred) {
2319
+ const old = this._transferred;
2320
+ this._transferred = transferred;
2321
+ // A progress update can make the "transferred" value smaller (e.g. a
2322
+ // partial upload not completed by server, after which the "transferred"
2323
+ // value may reset to the value at the beginning of the request).
2324
+ if (this._transferred !== old) {
2325
+ this._notifyObservers();
2326
+ }
2327
+ }
2328
+ _transition(state) {
2329
+ if (this._state === state) {
2330
+ return;
2331
+ }
2332
+ switch (state) {
2333
+ case "canceling" /* CANCELING */:
2334
+ // TODO(andysoto):
2335
+ // assert(this.state_ === InternalTaskState.RUNNING ||
2336
+ // this.state_ === InternalTaskState.PAUSING);
2337
+ this._state = state;
2338
+ if (this._request !== undefined) {
2339
+ this._request.cancel();
2340
+ }
2341
+ break;
2342
+ case "pausing" /* PAUSING */:
2343
+ // TODO(andysoto):
2344
+ // assert(this.state_ === InternalTaskState.RUNNING);
2345
+ this._state = state;
2346
+ if (this._request !== undefined) {
2347
+ this._request.cancel();
2348
+ }
2349
+ break;
2350
+ case "running" /* RUNNING */:
2351
+ // TODO(andysoto):
2352
+ // assert(this.state_ === InternalTaskState.PAUSED ||
2353
+ // this.state_ === InternalTaskState.PAUSING);
2354
+ const wasPaused = this._state === "paused" /* PAUSED */;
2355
+ this._state = state;
2356
+ if (wasPaused) {
2357
+ this._notifyObservers();
2358
+ this._start();
2359
+ }
2360
+ break;
2361
+ case "paused" /* PAUSED */:
2362
+ // TODO(andysoto):
2363
+ // assert(this.state_ === InternalTaskState.PAUSING);
2364
+ this._state = state;
2365
+ this._notifyObservers();
2366
+ break;
2367
+ case "canceled" /* CANCELED */:
2368
+ // TODO(andysoto):
2369
+ // assert(this.state_ === InternalTaskState.PAUSED ||
2370
+ // this.state_ === InternalTaskState.CANCELING);
2371
+ this._error = canceled();
2372
+ this._state = state;
2373
+ this._notifyObservers();
2374
+ break;
2375
+ case "error" /* ERROR */:
2376
+ // TODO(andysoto):
2377
+ // assert(this.state_ === InternalTaskState.RUNNING ||
2378
+ // this.state_ === InternalTaskState.PAUSING ||
2379
+ // this.state_ === InternalTaskState.CANCELING);
2380
+ this._state = state;
2381
+ this._notifyObservers();
2382
+ break;
2383
+ case "success" /* SUCCESS */:
2384
+ // TODO(andysoto):
2385
+ // assert(this.state_ === InternalTaskState.RUNNING ||
2386
+ // this.state_ === InternalTaskState.PAUSING ||
2387
+ // this.state_ === InternalTaskState.CANCELING);
2388
+ this._state = state;
2389
+ this._notifyObservers();
2390
+ break;
2391
+ }
2392
+ }
2393
+ completeTransitions_() {
2394
+ switch (this._state) {
2395
+ case "pausing" /* PAUSING */:
2396
+ this._transition("paused" /* PAUSED */);
2397
+ break;
2398
+ case "canceling" /* CANCELING */:
2399
+ this._transition("canceled" /* CANCELED */);
2400
+ break;
2401
+ case "running" /* RUNNING */:
2402
+ this._start();
2403
+ break;
2404
+ }
2405
+ }
2406
+ /**
2407
+ * A snapshot of the current task state.
2408
+ */
2409
+ get snapshot() {
2410
+ const externalState = taskStateFromInternalTaskState(this._state);
2411
+ return {
2412
+ bytesTransferred: this._transferred,
2413
+ totalBytes: this._blob.size(),
2414
+ state: externalState,
2415
+ metadata: this._metadata,
2416
+ task: this,
2417
+ ref: this._ref
2418
+ };
2419
+ }
2420
+ /**
2421
+ * Adds a callback for an event.
2422
+ * @param type - The type of event to listen for.
2423
+ * @param nextOrObserver -
2424
+ * The `next` function, which gets called for each item in
2425
+ * the event stream, or an observer object with some or all of these three
2426
+ * properties (`next`, `error`, `complete`).
2427
+ * @param error - A function that gets called with a `StorageError`
2428
+ * if the event stream ends due to an error.
2429
+ * @param completed - A function that gets called if the
2430
+ * event stream ends normally.
2431
+ * @returns
2432
+ * If only the event argument is passed, returns a function you can use to
2433
+ * add callbacks (see the examples above). If more than just the event
2434
+ * argument is passed, returns a function you can call to unregister the
2435
+ * callbacks.
2436
+ */
2437
+ on(type, nextOrObserver, error, completed) {
2438
+ const observer = new Observer(nextOrObserver || undefined, error || undefined, completed || undefined);
2439
+ this._addObserver(observer);
2440
+ return () => {
2441
+ this._removeObserver(observer);
2442
+ };
2443
+ }
2444
+ /**
2445
+ * This object behaves like a Promise, and resolves with its snapshot data
2446
+ * when the upload completes.
2447
+ * @param onFulfilled - The fulfillment callback. Promise chaining works as normal.
2448
+ * @param onRejected - The rejection callback.
2449
+ */
2450
+ then(onFulfilled, onRejected) {
2451
+ // These casts are needed so that TypeScript can infer the types of the
2452
+ // resulting Promise.
2453
+ return this._promise.then(onFulfilled, onRejected);
2454
+ }
2455
+ /**
2456
+ * Equivalent to calling `then(null, onRejected)`.
2457
+ */
2458
+ catch(onRejected) {
2459
+ return this.then(null, onRejected);
2460
+ }
2461
+ /**
2462
+ * Adds the given observer.
2463
+ */
2464
+ _addObserver(observer) {
2465
+ this._observers.push(observer);
2466
+ this._notifyObserver(observer);
2467
+ }
2468
+ /**
2469
+ * Removes the given observer.
2470
+ */
2471
+ _removeObserver(observer) {
2472
+ const i = this._observers.indexOf(observer);
2473
+ if (i !== -1) {
2474
+ this._observers.splice(i, 1);
2475
+ }
2476
+ }
2477
+ _notifyObservers() {
2478
+ this._finishPromise();
2479
+ const observers = this._observers.slice();
2480
+ observers.forEach(observer => {
2481
+ this._notifyObserver(observer);
2482
+ });
2483
+ }
2484
+ _finishPromise() {
2485
+ if (this._resolve !== undefined) {
2486
+ let triggered = true;
2487
+ switch (taskStateFromInternalTaskState(this._state)) {
2488
+ case TaskState.SUCCESS:
2489
+ async(this._resolve.bind(null, this.snapshot))();
2490
+ break;
2491
+ case TaskState.CANCELED:
2492
+ case TaskState.ERROR:
2493
+ const toCall = this._reject;
2494
+ async(toCall.bind(null, this._error))();
2495
+ break;
2496
+ default:
2497
+ triggered = false;
2498
+ break;
2499
+ }
2500
+ if (triggered) {
2501
+ this._resolve = undefined;
2502
+ this._reject = undefined;
2503
+ }
2504
+ }
2505
+ }
2506
+ _notifyObserver(observer) {
2507
+ const externalState = taskStateFromInternalTaskState(this._state);
2508
+ switch (externalState) {
2509
+ case TaskState.RUNNING:
2510
+ case TaskState.PAUSED:
2511
+ if (observer.next) {
2512
+ async(observer.next.bind(observer, this.snapshot))();
2513
+ }
2514
+ break;
2515
+ case TaskState.SUCCESS:
2516
+ if (observer.complete) {
2517
+ async(observer.complete.bind(observer))();
2518
+ }
2519
+ break;
2520
+ case TaskState.CANCELED:
2521
+ case TaskState.ERROR:
2522
+ if (observer.error) {
2523
+ async(observer.error.bind(observer, this._error))();
2524
+ }
2525
+ break;
2526
+ default:
2527
+ // TODO(andysoto): assert(false);
2528
+ if (observer.error) {
2529
+ async(observer.error.bind(observer, this._error))();
2530
+ }
2531
+ }
2532
+ }
2533
+ /**
2534
+ * Resumes a paused task. Has no effect on a currently running or failed task.
2535
+ * @returns True if the operation took effect, false if ignored.
2536
+ */
2537
+ resume() {
2538
+ const valid = this._state === "paused" /* PAUSED */ ||
2539
+ this._state === "pausing" /* PAUSING */;
2540
+ if (valid) {
2541
+ this._transition("running" /* RUNNING */);
2542
+ }
2543
+ return valid;
2544
+ }
2545
+ /**
2546
+ * Pauses a currently running task. Has no effect on a paused or failed task.
2547
+ * @returns True if the operation took effect, false if ignored.
2548
+ */
2549
+ pause() {
2550
+ const valid = this._state === "running" /* RUNNING */;
2551
+ if (valid) {
2552
+ this._transition("pausing" /* PAUSING */);
2553
+ }
2554
+ return valid;
2555
+ }
2556
+ /**
2557
+ * Cancels a currently running or paused task. Has no effect on a complete or
2558
+ * failed task.
2559
+ * @returns True if the operation took effect, false if ignored.
2560
+ */
2561
+ cancel() {
2562
+ const valid = this._state === "running" /* RUNNING */ ||
2563
+ this._state === "pausing" /* PAUSING */;
2564
+ if (valid) {
2565
+ this._transition("canceling" /* CANCELING */);
2566
+ }
2567
+ return valid;
2568
+ }
2569
+ }
2570
+
2571
+ /**
2572
+ * @license
2573
+ * Copyright 2019 Google LLC
2574
+ *
2575
+ * Licensed under the Apache License, Version 2.0 (the "License");
2576
+ * you may not use this file except in compliance with the License.
2577
+ * You may obtain a copy of the License at
2578
+ *
2579
+ * http://www.apache.org/licenses/LICENSE-2.0
2580
+ *
2581
+ * Unless required by applicable law or agreed to in writing, software
2582
+ * distributed under the License is distributed on an "AS IS" BASIS,
2583
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2584
+ * See the License for the specific language governing permissions and
2585
+ * limitations under the License.
2586
+ */
2587
+ /**
2588
+ * Provides methods to interact with a bucket in the Firebase Storage service.
2589
+ * @internal
2590
+ * @param _location - An fbs.location, or the URL at
2591
+ * which to base this object, in one of the following forms:
2592
+ * gs://<bucket>/<object-path>
2593
+ * http[s]://firebasestorage.googleapis.com/
2594
+ * <api-version>/b/<bucket>/o/<object-path>
2595
+ * Any query or fragment strings will be ignored in the http[s]
2596
+ * format. If no value is passed, the storage object will use a URL based on
2597
+ * the project ID of the base firebase.App instance.
2598
+ */
2599
+ class Reference {
2600
+ constructor(_service, location) {
2601
+ this._service = _service;
2602
+ if (location instanceof Location) {
2603
+ this._location = location;
2604
+ }
2605
+ else {
2606
+ this._location = Location.makeFromUrl(location, _service.host);
2607
+ }
2608
+ }
2609
+ /**
2610
+ * Returns the URL for the bucket and path this object references,
2611
+ * in the form gs://<bucket>/<object-path>
2612
+ * @override
2613
+ */
2614
+ toString() {
2615
+ return 'gs://' + this._location.bucket + '/' + this._location.path;
2616
+ }
2617
+ _newRef(service, location) {
2618
+ return new Reference(service, location);
2619
+ }
2620
+ /**
2621
+ * A reference to the root of this object's bucket.
2622
+ */
2623
+ get root() {
2624
+ const location = new Location(this._location.bucket, '');
2625
+ return this._newRef(this._service, location);
2626
+ }
2627
+ /**
2628
+ * The name of the bucket containing this reference's object.
2629
+ */
2630
+ get bucket() {
2631
+ return this._location.bucket;
2632
+ }
2633
+ /**
2634
+ * The full path of this object.
2635
+ */
2636
+ get fullPath() {
2637
+ return this._location.path;
2638
+ }
2639
+ /**
2640
+ * The short name of this object, which is the last component of the full path.
2641
+ * For example, if fullPath is 'full/path/image.png', name is 'image.png'.
2642
+ */
2643
+ get name() {
2644
+ return lastComponent(this._location.path);
2645
+ }
2646
+ /**
2647
+ * The `StorageService` instance this `StorageReference` is associated with.
2648
+ */
2649
+ get storage() {
2650
+ return this._service;
2651
+ }
2652
+ /**
2653
+ * A `StorageReference` pointing to the parent location of this `StorageReference`, or null if
2654
+ * this reference is the root.
2655
+ */
2656
+ get parent() {
2657
+ const newPath = parent(this._location.path);
2658
+ if (newPath === null) {
2659
+ return null;
2660
+ }
2661
+ const location = new Location(this._location.bucket, newPath);
2662
+ return new Reference(this._service, location);
2663
+ }
2664
+ /**
2665
+ * Utility function to throw an error in methods that do not accept a root reference.
2666
+ */
2667
+ _throwIfRoot(name) {
2668
+ if (this._location.path === '') {
2669
+ throw invalidRootOperation(name);
2670
+ }
2671
+ }
2672
+ }
2673
+ /**
2674
+ * Uploads data to this object's location.
2675
+ * The upload is not resumable.
2676
+ *
2677
+ * @param ref - StorageReference where data should be uploaded.
2678
+ * @param data - The data to upload.
2679
+ * @param metadata - Metadata for the newly uploaded data.
2680
+ * @returns A Promise containing an UploadResult
2681
+ */
2682
+ function uploadBytes$1(ref, data, metadata) {
2683
+ ref._throwIfRoot('uploadBytes');
2684
+ const requestInfo = multipartUpload(ref.storage, ref._location, getMappings(), new FbsBlob(data, true), metadata);
2685
+ return ref.storage
2686
+ .makeRequestWithTokens(requestInfo, newConnection)
2687
+ .then(finalMetadata => {
2688
+ return {
2689
+ metadata: finalMetadata,
2690
+ ref
2691
+ };
2692
+ });
2693
+ }
2694
+ /**
2695
+ * Uploads data to this object's location.
2696
+ * The upload can be paused and resumed, and exposes progress updates.
2697
+ * @public
2698
+ * @param ref - StorageReference where data should be uploaded.
2699
+ * @param data - The data to upload.
2700
+ * @param metadata - Metadata for the newly uploaded data.
2701
+ * @returns An UploadTask
2702
+ */
2703
+ function uploadBytesResumable$1(ref, data, metadata) {
2704
+ ref._throwIfRoot('uploadBytesResumable');
2705
+ return new UploadTask(ref, new FbsBlob(data), metadata);
2706
+ }
2707
+ /**
2708
+ * Uploads a string to this object's location.
2709
+ * The upload is not resumable.
2710
+ * @public
2711
+ * @param ref - StorageReference where string should be uploaded.
2712
+ * @param value - The string to upload.
2713
+ * @param format - The format of the string to upload.
2714
+ * @param metadata - Metadata for the newly uploaded string.
2715
+ * @returns A Promise containing an UploadResult
2716
+ */
2717
+ function uploadString$1(ref, value, format = StringFormat.RAW, metadata) {
2718
+ ref._throwIfRoot('uploadString');
2719
+ const data = dataFromString(format, value);
2720
+ const metadataClone = Object.assign({}, metadata);
2721
+ if (metadataClone['contentType'] == null && data.contentType != null) {
2722
+ metadataClone['contentType'] = data.contentType;
2723
+ }
2724
+ return uploadBytes$1(ref, data.data, metadataClone);
2725
+ }
2726
+ /**
2727
+ * List all items (files) and prefixes (folders) under this storage reference.
2728
+ *
2729
+ * This is a helper method for calling list() repeatedly until there are
2730
+ * no more results. The default pagination size is 1000.
2731
+ *
2732
+ * Note: The results may not be consistent if objects are changed while this
2733
+ * operation is running.
2734
+ *
2735
+ * Warning: listAll may potentially consume too many resources if there are
2736
+ * too many results.
2737
+ * @public
2738
+ * @param ref - StorageReference to get list from.
2739
+ *
2740
+ * @returns A Promise that resolves with all the items and prefixes under
2741
+ * the current storage reference. `prefixes` contains references to
2742
+ * sub-directories and `items` contains references to objects in this
2743
+ * folder. `nextPageToken` is never returned.
2744
+ */
2745
+ function listAll$1(ref) {
2746
+ const accumulator = {
2747
+ prefixes: [],
2748
+ items: []
2749
+ };
2750
+ return listAllHelper(ref, accumulator).then(() => accumulator);
2751
+ }
2752
+ /**
2753
+ * Separated from listAll because async functions can't use "arguments".
2754
+ * @param ref
2755
+ * @param accumulator
2756
+ * @param pageToken
2757
+ */
2758
+ async function listAllHelper(ref, accumulator, pageToken) {
2759
+ const opt = {
2760
+ // maxResults is 1000 by default.
2761
+ pageToken
2762
+ };
2763
+ const nextPage = await list$1(ref, opt);
2764
+ accumulator.prefixes.push(...nextPage.prefixes);
2765
+ accumulator.items.push(...nextPage.items);
2766
+ if (nextPage.nextPageToken != null) {
2767
+ await listAllHelper(ref, accumulator, nextPage.nextPageToken);
2768
+ }
2769
+ }
2770
+ /**
2771
+ * List items (files) and prefixes (folders) under this storage reference.
2772
+ *
2773
+ * List API is only available for Firebase Rules Version 2.
2774
+ *
2775
+ * GCS is a key-blob store. Firebase Storage imposes the semantic of '/'
2776
+ * delimited folder structure.
2777
+ * Refer to GCS's List API if you want to learn more.
2778
+ *
2779
+ * To adhere to Firebase Rules's Semantics, Firebase Storage does not
2780
+ * support objects whose paths end with "/" or contain two consecutive
2781
+ * "/"s. Firebase Storage List API will filter these unsupported objects.
2782
+ * list() may fail if there are too many unsupported objects in the bucket.
2783
+ * @public
2784
+ *
2785
+ * @param ref - StorageReference to get list from.
2786
+ * @param options - See ListOptions for details.
2787
+ * @returns A Promise that resolves with the items and prefixes.
2788
+ * `prefixes` contains references to sub-folders and `items`
2789
+ * contains references to objects in this folder. `nextPageToken`
2790
+ * can be used to get the rest of the results.
2791
+ */
2792
+ function list$1(ref, options) {
2793
+ if (options != null) {
2794
+ if (typeof options.maxResults === 'number') {
2795
+ validateNumber('options.maxResults',
2796
+ /* minValue= */ 1,
2797
+ /* maxValue= */ 1000, options.maxResults);
2798
+ }
2799
+ }
2800
+ const op = options || {};
2801
+ const requestInfo = list$2(ref.storage, ref._location,
2802
+ /*delimiter= */ '/', op.pageToken, op.maxResults);
2803
+ return ref.storage.makeRequestWithTokens(requestInfo, newConnection);
2804
+ }
2805
+ /**
2806
+ * A `Promise` that resolves with the metadata for this object. If this
2807
+ * object doesn't exist or metadata cannot be retreived, the promise is
2808
+ * rejected.
2809
+ * @public
2810
+ * @param ref - StorageReference to get metadata from.
2811
+ */
2812
+ function getMetadata$1(ref) {
2813
+ ref._throwIfRoot('getMetadata');
2814
+ const requestInfo = getMetadata$2(ref.storage, ref._location, getMappings());
2815
+ return ref.storage.makeRequestWithTokens(requestInfo, newConnection);
2816
+ }
2817
+ /**
2818
+ * Updates the metadata for this object.
2819
+ * @public
2820
+ * @param ref - StorageReference to update metadata for.
2821
+ * @param metadata - The new metadata for the object.
2822
+ * Only values that have been explicitly set will be changed. Explicitly
2823
+ * setting a value to null will remove the metadata.
2824
+ * @returns A `Promise` that resolves
2825
+ * with the new metadata for this object.
2826
+ * See `firebaseStorage.Reference.prototype.getMetadata`
2827
+ */
2828
+ function updateMetadata$1(ref, metadata) {
2829
+ ref._throwIfRoot('updateMetadata');
2830
+ const requestInfo = updateMetadata$2(ref.storage, ref._location, metadata, getMappings());
2831
+ return ref.storage.makeRequestWithTokens(requestInfo, newConnection);
2832
+ }
2833
+ /**
2834
+ * Returns the download URL for the given Reference.
2835
+ * @public
2836
+ * @returns A `Promise` that resolves with the download
2837
+ * URL for this object.
2838
+ */
2839
+ function getDownloadURL$1(ref) {
2840
+ ref._throwIfRoot('getDownloadURL');
2841
+ const requestInfo = getDownloadUrl(ref.storage, ref._location, getMappings());
2842
+ return ref.storage
2843
+ .makeRequestWithTokens(requestInfo, newConnection)
2844
+ .then(url => {
2845
+ if (url === null) {
2846
+ throw noDownloadURL();
2847
+ }
2848
+ return url;
2849
+ });
2850
+ }
2851
+ /**
2852
+ * Deletes the object at this location.
2853
+ * @public
2854
+ * @param ref - StorageReference for object to delete.
2855
+ * @returns A `Promise` that resolves if the deletion succeeds.
2856
+ */
2857
+ function deleteObject$1(ref) {
2858
+ ref._throwIfRoot('deleteObject');
2859
+ const requestInfo = deleteObject$2(ref.storage, ref._location);
2860
+ return ref.storage.makeRequestWithTokens(requestInfo, newConnection);
2861
+ }
2862
+ /**
2863
+ * Returns reference for object obtained by appending `childPath` to `ref`.
2864
+ *
2865
+ * @param ref - StorageReference to get child of.
2866
+ * @param childPath - Child path from provided ref.
2867
+ * @returns A reference to the object obtained by
2868
+ * appending childPath, removing any duplicate, beginning, or trailing
2869
+ * slashes.
2870
+ *
2871
+ */
2872
+ function _getChild$1(ref, childPath) {
2873
+ const newPath = child(ref._location.path, childPath);
2874
+ const location = new Location(ref._location.bucket, newPath);
2875
+ return new Reference(ref.storage, location);
2876
+ }
2877
+
2878
+ /**
2879
+ * @license
2880
+ * Copyright 2017 Google LLC
2881
+ *
2882
+ * Licensed under the Apache License, Version 2.0 (the "License");
2883
+ * you may not use this file except in compliance with the License.
2884
+ * You may obtain a copy of the License at
2885
+ *
2886
+ * http://www.apache.org/licenses/LICENSE-2.0
2887
+ *
2888
+ * Unless required by applicable law or agreed to in writing, software
2889
+ * distributed under the License is distributed on an "AS IS" BASIS,
2890
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2891
+ * See the License for the specific language governing permissions and
2892
+ * limitations under the License.
2893
+ */
2894
+ function isUrl(path) {
2895
+ return /^[A-Za-z]+:\/\//.test(path);
2896
+ }
2897
+ /**
2898
+ * Returns a firebaseStorage.Reference for the given url.
2899
+ */
2900
+ function refFromURL(service, url) {
2901
+ return new Reference(service, url);
2902
+ }
2903
+ /**
2904
+ * Returns a firebaseStorage.Reference for the given path in the default
2905
+ * bucket.
2906
+ */
2907
+ function refFromPath(ref, path) {
2908
+ if (ref instanceof FirebaseStorageImpl) {
2909
+ const service = ref;
2910
+ if (service._bucket == null) {
2911
+ throw noDefaultBucket();
2912
+ }
2913
+ const reference = new Reference(service, service._bucket);
2914
+ if (path != null) {
2915
+ return refFromPath(reference, path);
2916
+ }
2917
+ else {
2918
+ return reference;
2919
+ }
2920
+ }
2921
+ else {
2922
+ // ref is a Reference
2923
+ if (path !== undefined) {
2924
+ return _getChild$1(ref, path);
2925
+ }
2926
+ else {
2927
+ return ref;
2928
+ }
2929
+ }
2930
+ }
2931
+ function ref$1(serviceOrRef, pathOrUrl) {
2932
+ if (pathOrUrl && isUrl(pathOrUrl)) {
2933
+ if (serviceOrRef instanceof FirebaseStorageImpl) {
2934
+ return refFromURL(serviceOrRef, pathOrUrl);
2935
+ }
2936
+ else {
2937
+ throw invalidArgument('To use ref(service, url), the first argument must be a Storage instance.');
2938
+ }
2939
+ }
2940
+ else {
2941
+ return refFromPath(serviceOrRef, pathOrUrl);
2942
+ }
2943
+ }
2944
+ function extractBucket(host, config) {
2945
+ const bucketString = config === null || config === void 0 ? void 0 : config[CONFIG_STORAGE_BUCKET_KEY];
2946
+ if (bucketString == null) {
2947
+ return null;
2948
+ }
2949
+ return Location.makeFromBucketSpec(bucketString, host);
2950
+ }
2951
+ function connectStorageEmulator$1(storage, host, port, options = {}) {
2952
+ storage.host = `${host}:${port}`;
2953
+ storage._protocol = 'http';
2954
+ const { mockUserToken } = options;
2955
+ if (mockUserToken) {
2956
+ storage._overrideAuthToken =
2957
+ typeof mockUserToken === 'string'
2958
+ ? mockUserToken
2959
+ : createMockUserToken(mockUserToken, storage.app.options.projectId);
2960
+ }
2961
+ }
2962
+ /**
2963
+ * A service that provides Firebase Storage Reference instances.
2964
+ * @param opt_url - gs:// url to a custom Storage Bucket
2965
+ *
2966
+ * @internal
2967
+ */
2968
+ class FirebaseStorageImpl {
2969
+ constructor(
2970
+ /**
2971
+ * FirebaseApp associated with this StorageService instance.
2972
+ */
2973
+ app, _authProvider,
2974
+ /**
2975
+ * @internal
2976
+ */
2977
+ _appCheckProvider,
2978
+ /**
2979
+ * @internal
2980
+ */
2981
+ _url, _firebaseVersion) {
2982
+ this.app = app;
2983
+ this._authProvider = _authProvider;
2984
+ this._appCheckProvider = _appCheckProvider;
2985
+ this._url = _url;
2986
+ this._firebaseVersion = _firebaseVersion;
2987
+ this._bucket = null;
2988
+ /**
2989
+ * This string can be in the formats:
2990
+ * - host
2991
+ * - host:port
2992
+ */
2993
+ this._host = DEFAULT_HOST;
2994
+ this._protocol = 'https';
2995
+ this._appId = null;
2996
+ this._deleted = false;
2997
+ this._maxOperationRetryTime = DEFAULT_MAX_OPERATION_RETRY_TIME;
2998
+ this._maxUploadRetryTime = DEFAULT_MAX_UPLOAD_RETRY_TIME;
2999
+ this._requests = new Set();
3000
+ if (_url != null) {
3001
+ this._bucket = Location.makeFromBucketSpec(_url, this._host);
3002
+ }
3003
+ else {
3004
+ this._bucket = extractBucket(this._host, this.app.options);
3005
+ }
3006
+ }
3007
+ /**
3008
+ * The host string for this service, in the form of `host` or
3009
+ * `host:port`.
3010
+ */
3011
+ get host() {
3012
+ return this._host;
3013
+ }
3014
+ set host(host) {
3015
+ this._host = host;
3016
+ if (this._url != null) {
3017
+ this._bucket = Location.makeFromBucketSpec(this._url, host);
3018
+ }
3019
+ else {
3020
+ this._bucket = extractBucket(host, this.app.options);
3021
+ }
3022
+ }
3023
+ /**
3024
+ * The maximum time to retry uploads in milliseconds.
3025
+ */
3026
+ get maxUploadRetryTime() {
3027
+ return this._maxUploadRetryTime;
3028
+ }
3029
+ set maxUploadRetryTime(time) {
3030
+ validateNumber('time',
3031
+ /* minValue=*/ 0,
3032
+ /* maxValue= */ Number.POSITIVE_INFINITY, time);
3033
+ this._maxUploadRetryTime = time;
3034
+ }
3035
+ /**
3036
+ * The maximum time to retry operations other than uploads or downloads in
3037
+ * milliseconds.
3038
+ */
3039
+ get maxOperationRetryTime() {
3040
+ return this._maxOperationRetryTime;
3041
+ }
3042
+ set maxOperationRetryTime(time) {
3043
+ validateNumber('time',
3044
+ /* minValue=*/ 0,
3045
+ /* maxValue= */ Number.POSITIVE_INFINITY, time);
3046
+ this._maxOperationRetryTime = time;
3047
+ }
3048
+ async _getAuthToken() {
3049
+ if (this._overrideAuthToken) {
3050
+ return this._overrideAuthToken;
3051
+ }
3052
+ const auth = this._authProvider.getImmediate({ optional: true });
3053
+ if (auth) {
3054
+ const tokenData = await auth.getToken();
3055
+ if (tokenData !== null) {
3056
+ return tokenData.accessToken;
3057
+ }
3058
+ }
3059
+ return null;
3060
+ }
3061
+ async _getAppCheckToken() {
3062
+ const appCheck = this._appCheckProvider.getImmediate({ optional: true });
3063
+ if (appCheck) {
3064
+ const result = await appCheck.getToken();
3065
+ // TODO: What do we want to do if there is an error getting the token?
3066
+ // Context: appCheck.getToken() will never throw even if an error happened. In the error case, a dummy token will be
3067
+ // returned along with an error field describing the error. In general, we shouldn't care about the error condition and just use
3068
+ // the token (actual or dummy) to send requests.
3069
+ return result.token;
3070
+ }
3071
+ return null;
3072
+ }
3073
+ /**
3074
+ * Stop running requests and prevent more from being created.
3075
+ */
3076
+ _delete() {
3077
+ if (!this._deleted) {
3078
+ this._deleted = true;
3079
+ this._requests.forEach(request => request.cancel());
3080
+ this._requests.clear();
3081
+ }
3082
+ return Promise.resolve();
3083
+ }
3084
+ /**
3085
+ * Returns a new firebaseStorage.Reference object referencing this StorageService
3086
+ * at the given Location.
3087
+ */
3088
+ _makeStorageReference(loc) {
3089
+ return new Reference(this, loc);
3090
+ }
3091
+ /**
3092
+ * @param requestInfo - HTTP RequestInfo object
3093
+ * @param authToken - Firebase auth token
3094
+ */
3095
+ _makeRequest(requestInfo, requestFactory, authToken, appCheckToken) {
3096
+ if (!this._deleted) {
3097
+ const request = makeRequest(requestInfo, this._appId, authToken, appCheckToken, requestFactory, this._firebaseVersion);
3098
+ this._requests.add(request);
3099
+ // Request removes itself from set when complete.
3100
+ request.getPromise().then(() => this._requests.delete(request), () => this._requests.delete(request));
3101
+ return request;
3102
+ }
3103
+ else {
3104
+ return new FailRequest(appDeleted());
3105
+ }
3106
+ }
3107
+ async makeRequestWithTokens(requestInfo, requestFactory) {
3108
+ const [authToken, appCheckToken] = await Promise.all([
3109
+ this._getAuthToken(),
3110
+ this._getAppCheckToken()
3111
+ ]);
3112
+ return this._makeRequest(requestInfo, requestFactory, authToken, appCheckToken).getPromise();
3113
+ }
3114
+ }
3115
+
3116
+ const name = "@firebase/storage";
3117
+ const version = "0.8.5";
3118
+
3119
+ /**
3120
+ * @license
3121
+ * Copyright 2020 Google LLC
3122
+ *
3123
+ * Licensed under the Apache License, Version 2.0 (the "License");
3124
+ * you may not use this file except in compliance with the License.
3125
+ * You may obtain a copy of the License at
3126
+ *
3127
+ * http://www.apache.org/licenses/LICENSE-2.0
3128
+ *
3129
+ * Unless required by applicable law or agreed to in writing, software
3130
+ * distributed under the License is distributed on an "AS IS" BASIS,
3131
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3132
+ * See the License for the specific language governing permissions and
3133
+ * limitations under the License.
3134
+ */
3135
+ /**
3136
+ * Type constant for Firebase Storage.
3137
+ */
3138
+ const STORAGE_TYPE = 'storage';
3139
+
3140
+ /**
3141
+ * @license
3142
+ * Copyright 2020 Google LLC
3143
+ *
3144
+ * Licensed under the Apache License, Version 2.0 (the "License");
3145
+ * you may not use this file except in compliance with the License.
3146
+ * You may obtain a copy of the License at
3147
+ *
3148
+ * http://www.apache.org/licenses/LICENSE-2.0
3149
+ *
3150
+ * Unless required by applicable law or agreed to in writing, software
3151
+ * distributed under the License is distributed on an "AS IS" BASIS,
3152
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3153
+ * See the License for the specific language governing permissions and
3154
+ * limitations under the License.
3155
+ */
3156
+ /**
3157
+ * Uploads data to this object's location.
3158
+ * The upload is not resumable.
3159
+ * @public
3160
+ * @param ref - {@link StorageReference} where data should be uploaded.
3161
+ * @param data - The data to upload.
3162
+ * @param metadata - Metadata for the data to upload.
3163
+ * @returns A Promise containing an UploadResult
3164
+ */
3165
+ function uploadBytes(ref, data, metadata) {
3166
+ ref = getModularInstance(ref);
3167
+ return uploadBytes$1(ref, data, metadata);
3168
+ }
3169
+ /**
3170
+ * Uploads a string to this object's location.
3171
+ * The upload is not resumable.
3172
+ * @public
3173
+ * @param ref - {@link StorageReference} where string should be uploaded.
3174
+ * @param value - The string to upload.
3175
+ * @param format - The format of the string to upload.
3176
+ * @param metadata - Metadata for the string to upload.
3177
+ * @returns A Promise containing an UploadResult
3178
+ */
3179
+ function uploadString(ref, value, format, metadata) {
3180
+ ref = getModularInstance(ref);
3181
+ return uploadString$1(ref, value, format, metadata);
3182
+ }
3183
+ /**
3184
+ * Uploads data to this object's location.
3185
+ * The upload can be paused and resumed, and exposes progress updates.
3186
+ * @public
3187
+ * @param ref - {@link StorageReference} where data should be uploaded.
3188
+ * @param data - The data to upload.
3189
+ * @param metadata - Metadata for the data to upload.
3190
+ * @returns An UploadTask
3191
+ */
3192
+ function uploadBytesResumable(ref, data, metadata) {
3193
+ ref = getModularInstance(ref);
3194
+ return uploadBytesResumable$1(ref, data, metadata);
3195
+ }
3196
+ /**
3197
+ * A `Promise` that resolves with the metadata for this object. If this
3198
+ * object doesn't exist or metadata cannot be retreived, the promise is
3199
+ * rejected.
3200
+ * @public
3201
+ * @param ref - {@link StorageReference} to get metadata from.
3202
+ */
3203
+ function getMetadata(ref) {
3204
+ ref = getModularInstance(ref);
3205
+ return getMetadata$1(ref);
3206
+ }
3207
+ /**
3208
+ * Updates the metadata for this object.
3209
+ * @public
3210
+ * @param ref - {@link StorageReference} to update metadata for.
3211
+ * @param metadata - The new metadata for the object.
3212
+ * Only values that have been explicitly set will be changed. Explicitly
3213
+ * setting a value to null will remove the metadata.
3214
+ * @returns A `Promise` that resolves with the new metadata for this object.
3215
+ */
3216
+ function updateMetadata(ref, metadata) {
3217
+ ref = getModularInstance(ref);
3218
+ return updateMetadata$1(ref, metadata);
3219
+ }
3220
+ /**
3221
+ * List items (files) and prefixes (folders) under this storage reference.
3222
+ *
3223
+ * List API is only available for Firebase Rules Version 2.
3224
+ *
3225
+ * GCS is a key-blob store. Firebase Storage imposes the semantic of '/'
3226
+ * delimited folder structure.
3227
+ * Refer to GCS's List API if you want to learn more.
3228
+ *
3229
+ * To adhere to Firebase Rules's Semantics, Firebase Storage does not
3230
+ * support objects whose paths end with "/" or contain two consecutive
3231
+ * "/"s. Firebase Storage List API will filter these unsupported objects.
3232
+ * list() may fail if there are too many unsupported objects in the bucket.
3233
+ * @public
3234
+ *
3235
+ * @param ref - {@link StorageReference} to get list from.
3236
+ * @param options - See {@link ListOptions} for details.
3237
+ * @returns A `Promise` that resolves with the items and prefixes.
3238
+ * `prefixes` contains references to sub-folders and `items`
3239
+ * contains references to objects in this folder. `nextPageToken`
3240
+ * can be used to get the rest of the results.
3241
+ */
3242
+ function list(ref, options) {
3243
+ ref = getModularInstance(ref);
3244
+ return list$1(ref, options);
3245
+ }
3246
+ /**
3247
+ * List all items (files) and prefixes (folders) under this storage reference.
3248
+ *
3249
+ * This is a helper method for calling list() repeatedly until there are
3250
+ * no more results. The default pagination size is 1000.
3251
+ *
3252
+ * Note: The results may not be consistent if objects are changed while this
3253
+ * operation is running.
3254
+ *
3255
+ * Warning: `listAll` may potentially consume too many resources if there are
3256
+ * too many results.
3257
+ * @public
3258
+ * @param ref - {@link StorageReference} to get list from.
3259
+ *
3260
+ * @returns A `Promise` that resolves with all the items and prefixes under
3261
+ * the current storage reference. `prefixes` contains references to
3262
+ * sub-directories and `items` contains references to objects in this
3263
+ * folder. `nextPageToken` is never returned.
3264
+ */
3265
+ function listAll(ref) {
3266
+ ref = getModularInstance(ref);
3267
+ return listAll$1(ref);
3268
+ }
3269
+ /**
3270
+ * Returns the download URL for the given {@link StorageReference}.
3271
+ * @public
3272
+ * @param ref - {@link StorageReference} to get the download URL for.
3273
+ * @returns A `Promise` that resolves with the download
3274
+ * URL for this object.
3275
+ */
3276
+ function getDownloadURL(ref) {
3277
+ ref = getModularInstance(ref);
3278
+ return getDownloadURL$1(ref);
3279
+ }
3280
+ /**
3281
+ * Deletes the object at this location.
3282
+ * @public
3283
+ * @param ref - {@link StorageReference} for object to delete.
3284
+ * @returns A `Promise` that resolves if the deletion succeeds.
3285
+ */
3286
+ function deleteObject(ref) {
3287
+ ref = getModularInstance(ref);
3288
+ return deleteObject$1(ref);
3289
+ }
3290
+ function ref(serviceOrRef, pathOrUrl) {
3291
+ serviceOrRef = getModularInstance(serviceOrRef);
3292
+ return ref$1(serviceOrRef, pathOrUrl);
3293
+ }
3294
+ /**
3295
+ * @internal
3296
+ */
3297
+ function _getChild(ref, childPath) {
3298
+ return _getChild$1(ref, childPath);
3299
+ }
3300
+ /**
3301
+ * Gets a {@link FirebaseStorage} instance for the given Firebase app.
3302
+ * @public
3303
+ * @param app - Firebase app to get {@link FirebaseStorage} instance for.
3304
+ * @param bucketUrl - The gs:// url to your Firebase Storage Bucket.
3305
+ * If not passed, uses the app's default Storage Bucket.
3306
+ * @returns A {@link FirebaseStorage} instance.
3307
+ */
3308
+ function getStorage(app = getApp(), bucketUrl) {
3309
+ app = getModularInstance(app);
3310
+ const storageProvider = _getProvider(app, STORAGE_TYPE);
3311
+ const storageInstance = storageProvider.getImmediate({
3312
+ identifier: bucketUrl
3313
+ });
3314
+ return storageInstance;
3315
+ }
3316
+ /**
3317
+ * Modify this {@link FirebaseStorage} instance to communicate with the Cloud Storage emulator.
3318
+ *
3319
+ * @param storage - The {@link FirebaseStorage} instance
3320
+ * @param host - The emulator host (ex: localhost)
3321
+ * @param port - The emulator port (ex: 5001)
3322
+ * @param options - Emulator options. `options.mockUserToken` is the mock auth
3323
+ * token to use for unit testing Security Rules.
3324
+ * @public
3325
+ */
3326
+ function connectStorageEmulator(storage, host, port, options = {}) {
3327
+ connectStorageEmulator$1(storage, host, port, options);
3328
+ }
3329
+
3330
+ /**
3331
+ * Cloud Storage for Firebase
3332
+ *
3333
+ * @packageDocumentation
3334
+ */
3335
+ function factory(container, { instanceIdentifier: url }) {
3336
+ const app = container.getProvider('app').getImmediate();
3337
+ const authProvider = container.getProvider('auth-internal');
3338
+ const appCheckProvider = container.getProvider('app-check-internal');
3339
+ return new FirebaseStorageImpl(app, authProvider, appCheckProvider, url, SDK_VERSION);
3340
+ }
3341
+ function registerStorage() {
3342
+ _registerComponent(new Component(STORAGE_TYPE, factory, "PUBLIC" /* PUBLIC */).setMultipleInstances(true));
3343
+ //RUNTIME_ENV will be replaced during the compilation to "node" for nodejs and an empty string for browser
3344
+ registerVersion(name, version, 'node');
3345
+ // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation
3346
+ registerVersion(name, version, 'esm2017');
3347
+ }
3348
+ registerStorage();
3349
+
3350
+ export { StringFormat, FbsBlob as _FbsBlob, Location as _Location, TaskEvent as _TaskEvent, TaskState as _TaskState, UploadTask as _UploadTask, dataFromString as _dataFromString, _getChild, invalidArgument as _invalidArgument, invalidRootOperation as _invalidRootOperation, connectStorageEmulator, deleteObject, getDownloadURL, getMetadata, getStorage, list, listAll, ref, updateMetadata, uploadBytes, uploadBytesResumable, uploadString };
3351
+ //# sourceMappingURL=index.node.esm.js.map