@firebase/storage 0.9.10 → 0.9.11-20221010203322

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  #Unreleased
2
2
 
3
+ ## 0.9.11-20221010203322
4
+
5
+ ### Patch Changes
6
+
7
+ - [`4eb8145fb`](https://github.com/firebase/firebase-js-sdk/commit/4eb8145fb3b503884ea610e813be359127d1a705) [#6653](https://github.com/firebase/firebase-js-sdk/pull/6653) - Fixed bug where upload status wasn't being checked after an upload failure.
8
+ Implemented exponential backoff and max retry strategy.
9
+
10
+ * [`171b78b76`](https://github.com/firebase/firebase-js-sdk/commit/171b78b762826a640d267dd4dd172ad9459c4561) [#6673](https://github.com/firebase/firebase-js-sdk/pull/6673) - Handle IPv6 addresses in emulator autoinit.
11
+
12
+ * Updated dependencies [[`171b78b76`](https://github.com/firebase/firebase-js-sdk/commit/171b78b762826a640d267dd4dd172ad9459c4561), [`29d034072`](https://github.com/firebase/firebase-js-sdk/commit/29d034072c20af394ce384e42aa10a37d5dfcb18)]:
13
+ - @firebase/util@1.7.1-20221010203322
14
+ - @firebase/app@0.8.1-20221010203322
15
+ - @firebase/component@0.5.19-20221010203322
16
+
3
17
  ## 0.9.10
4
18
 
5
19
  ### Patch Changes
@@ -45,7 +45,11 @@ var DEFAULT_MAX_OPERATION_RETRY_TIME = 2 * 60 * 1000;
45
45
  *
46
46
  * The timeout for upload.
47
47
  */
48
- var DEFAULT_MAX_UPLOAD_RETRY_TIME = 10 * 60 * 1000;
48
+ var DEFAULT_MAX_UPLOAD_RETRY_TIME = 10 * 60 * 1000;
49
+ /**
50
+ * 1 second
51
+ */
52
+ var DEFAULT_MIN_SLEEP_TIME_MILLIS = 1000;
49
53
 
50
54
  /**
51
55
  * @license
@@ -73,9 +77,12 @@ var StorageError = /** @class */ (function (_super) {
73
77
  * @param code - A StorageErrorCode string to be prefixed with 'storage/' and
74
78
  * added to the end of the message.
75
79
  * @param message - Error message.
80
+ * @param status_ - Corresponding HTTP Status Code
76
81
  */
77
- function StorageError(code, message) {
82
+ function StorageError(code, message, status_) {
83
+ if (status_ === void 0) { status_ = 0; }
78
84
  var _this = _super.call(this, prependCode(code), "Firebase Storage: " + message + " (" + prependCode(code) + ")") || this;
85
+ _this.status_ = status_;
79
86
  /**
80
87
  * Stores custom error data unque to StorageError.
81
88
  */
@@ -86,6 +93,16 @@ var StorageError = /** @class */ (function (_super) {
86
93
  Object.setPrototypeOf(_this, StorageError.prototype);
87
94
  return _this;
88
95
  }
96
+ Object.defineProperty(StorageError.prototype, "status", {
97
+ get: function () {
98
+ return this.status_;
99
+ },
100
+ set: function (status) {
101
+ this.status_ = status;
102
+ },
103
+ enumerable: false,
104
+ configurable: true
105
+ });
89
106
  /**
90
107
  * Compares a StorageErrorCode against this error's code, filtering out the prefix.
91
108
  */
@@ -361,14 +378,20 @@ var FailRequest = /** @class */ (function () {
361
378
  * limitations under the License.
362
379
  */
363
380
  /**
364
- * @param f May be invoked
365
- * before the function returns.
366
- * @param callback Get all the arguments passed to the function
367
- * passed to f, including the initial boolean.
381
+ * Accepts a callback for an action to perform (`doRequest`),
382
+ * and then a callback for when the backoff has completed (`backoffCompleteCb`).
383
+ * The callback sent to start requires an argument to call (`onRequestComplete`).
384
+ * When `start` calls `doRequest`, it passes a callback for when the request has
385
+ * completed, `onRequestComplete`. Based on this, the backoff continues, with
386
+ * another call to `doRequest` and the above loop continues until the timeout
387
+ * is hit, or a successful response occurs.
388
+ * @description
389
+ * @param doRequest Callback to perform request
390
+ * @param backoffCompleteCb Callback to call when backoff has been completed
368
391
  */
369
- function start(f,
392
+ function start(doRequest,
370
393
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
371
- callback, timeout) {
394
+ backoffCompleteCb, timeout) {
372
395
  // TODO(andysoto): make this code cleaner (probably refactor into an actual
373
396
  // type instead of a bunch of functions with state shared in the closure)
374
397
  var waitSeconds = 1;
@@ -391,13 +414,13 @@ callback, timeout) {
391
414
  }
392
415
  if (!triggeredCallback) {
393
416
  triggeredCallback = true;
394
- callback.apply(null, args);
417
+ backoffCompleteCb.apply(null, args);
395
418
  }
396
419
  }
397
420
  function callWithDelay(millis) {
398
421
  retryTimeoutId = setTimeout(function () {
399
422
  retryTimeoutId = null;
400
- f(handler, canceled());
423
+ doRequest(responseHandler, canceled());
401
424
  }, millis);
402
425
  }
403
426
  function clearGlobalTimeout() {
@@ -405,7 +428,7 @@ callback, timeout) {
405
428
  clearTimeout(globalTimeoutId);
406
429
  }
407
430
  }
408
- function handler(success) {
431
+ function responseHandler(success) {
409
432
  var args = [];
410
433
  for (var _i = 1; _i < arguments.length; _i++) {
411
434
  args[_i - 1] = arguments[_i];
@@ -587,6 +610,43 @@ var ErrorCode;
587
610
  ErrorCode[ErrorCode["ABORT"] = 2] = "ABORT";
588
611
  })(ErrorCode || (ErrorCode = {}));
589
612
 
613
+ /**
614
+ * @license
615
+ * Copyright 2022 Google LLC
616
+ *
617
+ * Licensed under the Apache License, Version 2.0 (the "License");
618
+ * you may not use this file except in compliance with the License.
619
+ * You may obtain a copy of the License at
620
+ *
621
+ * http://www.apache.org/licenses/LICENSE-2.0
622
+ *
623
+ * Unless required by applicable law or agreed to in writing, software
624
+ * distributed under the License is distributed on an "AS IS" BASIS,
625
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
626
+ * See the License for the specific language governing permissions and
627
+ * limitations under the License.
628
+ */
629
+ /**
630
+ * Checks the status code to see if the action should be retried.
631
+ *
632
+ * @param status Current HTTP status code returned by server.
633
+ * @param additionalRetryCodes additional retry codes to check against
634
+ */
635
+ function isRetryStatusCode(status, additionalRetryCodes) {
636
+ // The codes for which to retry came from this page:
637
+ // https://cloud.google.com/storage/docs/exponential-backoff
638
+ var isFiveHundredCode = status >= 500 && status < 600;
639
+ var extraRetryCodes = [
640
+ // Request Timeout: web server didn't receive full request in time.
641
+ 408,
642
+ // Too Many Requests: you're getting rate-limited, basically.
643
+ 429
644
+ ];
645
+ var isExtraRetryCode = extraRetryCodes.indexOf(status) !== -1;
646
+ var isAdditionalRetryCode = additionalRetryCodes.indexOf(status) !== -1;
647
+ return isFiveHundredCode || isExtraRetryCode || isAdditionalRetryCode;
648
+ }
649
+
590
650
  /**
591
651
  * @license
592
652
  * Copyright 2017 Google LLC
@@ -612,8 +672,9 @@ var ErrorCode;
612
672
  * happens in the specified `callback_`.
613
673
  */
614
674
  var NetworkRequest = /** @class */ (function () {
615
- function NetworkRequest(url_, method_, headers_, body_, successCodes_, additionalRetryCodes_, callback_, errorCallback_, timeout_, progressCallback_, connectionFactory_) {
675
+ function NetworkRequest(url_, method_, headers_, body_, successCodes_, additionalRetryCodes_, callback_, errorCallback_, timeout_, progressCallback_, connectionFactory_, retry) {
616
676
  var _this = this;
677
+ if (retry === void 0) { retry = true; }
617
678
  this.url_ = url_;
618
679
  this.method_ = method_;
619
680
  this.headers_ = headers_;
@@ -625,6 +686,7 @@ var NetworkRequest = /** @class */ (function () {
625
686
  this.timeout_ = timeout_;
626
687
  this.progressCallback_ = progressCallback_;
627
688
  this.connectionFactory_ = connectionFactory_;
689
+ this.retry = retry;
628
690
  this.pendingConnection_ = null;
629
691
  this.backoffId_ = null;
630
692
  this.canceled_ = false;
@@ -649,9 +711,7 @@ var NetworkRequest = /** @class */ (function () {
649
711
  _this.pendingConnection_ = connection;
650
712
  var progressListener = function (progressEvent) {
651
713
  var loaded = progressEvent.loaded;
652
- var total = progressEvent.lengthComputable
653
- ? progressEvent.total
654
- : -1;
714
+ var total = progressEvent.lengthComputable ? progressEvent.total : -1;
655
715
  if (_this.progressCallback_ !== null) {
656
716
  _this.progressCallback_(loaded, total);
657
717
  }
@@ -670,7 +730,9 @@ var NetworkRequest = /** @class */ (function () {
670
730
  _this.pendingConnection_ = null;
671
731
  var hitServer = connection.getErrorCode() === ErrorCode.NO_ERROR;
672
732
  var status = connection.getStatus();
673
- if (!hitServer || _this.isRetryStatusCode_(status)) {
733
+ if ((!hitServer ||
734
+ isRetryStatusCode(status, _this.additionalRetryCodes_)) &&
735
+ _this.retry) {
674
736
  var wasCanceled = connection.getErrorCode() === ErrorCode.ABORT;
675
737
  backoffCallback(false, new RequestEndStatus(false, null, wasCanceled));
676
738
  return;
@@ -746,20 +808,6 @@ var NetworkRequest = /** @class */ (function () {
746
808
  this.pendingConnection_.abort();
747
809
  }
748
810
  };
749
- NetworkRequest.prototype.isRetryStatusCode_ = function (status) {
750
- // The codes for which to retry came from this page:
751
- // https://cloud.google.com/storage/docs/exponential-backoff
752
- var isFiveHundredCode = status >= 500 && status < 600;
753
- var extraRetryCodes = [
754
- // Request Timeout: web server didn't receive full request in time.
755
- 408,
756
- // Too Many Requests: you're getting rate-limited, basically.
757
- 429
758
- ];
759
- var isExtraRetryCode = extraRetryCodes.indexOf(status) !== -1;
760
- var isRequestSpecificRetryCode = this.additionalRetryCodes_.indexOf(status) !== -1;
761
- return isFiveHundredCode || isExtraRetryCode || isRequestSpecificRetryCode;
762
- };
763
811
  return NetworkRequest;
764
812
  }());
765
813
  /**
@@ -793,7 +841,8 @@ function addAppCheckHeader_(headers, appCheckToken) {
793
841
  headers['X-Firebase-AppCheck'] = appCheckToken;
794
842
  }
795
843
  }
796
- function makeRequest(requestInfo, appId, authToken, appCheckToken, requestFactory, firebaseVersion) {
844
+ function makeRequest(requestInfo, appId, authToken, appCheckToken, requestFactory, firebaseVersion, retry) {
845
+ if (retry === void 0) { retry = true; }
797
846
  var queryPart = makeQueryString(requestInfo.urlParams);
798
847
  var url = requestInfo.url + queryPart;
799
848
  var headers = Object.assign({}, requestInfo.headers);
@@ -801,7 +850,7 @@ function makeRequest(requestInfo, appId, authToken, appCheckToken, requestFactor
801
850
  addAuthHeader_(headers, authToken);
802
851
  addVersionHeader_(headers, firebaseVersion);
803
852
  addAppCheckHeader_(headers, appCheckToken);
804
- return new NetworkRequest(url, requestInfo.method, headers, requestInfo.body, requestInfo.successCodes, requestInfo.additionalRetryCodes, requestInfo.handler, requestInfo.errorHandler, requestInfo.timeout, requestInfo.progressCallback, requestFactory);
853
+ return new NetworkRequest(url, requestInfo.method, headers, requestInfo.body, requestInfo.successCodes, requestInfo.additionalRetryCodes, requestInfo.handler, requestInfo.errorHandler, requestInfo.timeout, requestInfo.progressCallback, requestFactory, retry);
805
854
  }
806
855
 
807
856
  /**
@@ -1633,6 +1682,7 @@ function sharedErrorHandler(location) {
1633
1682
  }
1634
1683
  }
1635
1684
  }
1685
+ newErr.status = xhr.getStatus();
1636
1686
  newErr.serverResponse = err.serverResponse;
1637
1687
  return newErr;
1638
1688
  }
@@ -1918,7 +1968,16 @@ function continueResumableUpload(location, service, url, blob, chunkSize, mappin
1918
1968
  }
1919
1969
  var startByte = status_.current;
1920
1970
  var endByte = startByte + bytesToUpload;
1921
- var uploadCommand = bytesToUpload === bytesLeft ? 'upload, finalize' : 'upload';
1971
+ var uploadCommand = '';
1972
+ if (bytesToUpload === 0) {
1973
+ uploadCommand = 'finalize';
1974
+ }
1975
+ else if (bytesLeft === bytesToUpload) {
1976
+ uploadCommand = 'upload, finalize';
1977
+ }
1978
+ else {
1979
+ uploadCommand = 'upload';
1980
+ }
1922
1981
  var headers = {
1923
1982
  'X-Goog-Upload-Command': uploadCommand,
1924
1983
  'X-Goog-Upload-Offset': "" + status_.current
@@ -2302,6 +2361,18 @@ var UploadTask = /** @class */ (function () {
2302
2361
  _this.completeTransitions_();
2303
2362
  }
2304
2363
  else {
2364
+ var backoffExpired = _this.isExponentialBackoffExpired();
2365
+ if (isRetryStatusCode(error.status, [])) {
2366
+ if (backoffExpired) {
2367
+ error = retryLimitExceeded();
2368
+ }
2369
+ else {
2370
+ _this.sleepTime = Math.max(_this.sleepTime * 2, DEFAULT_MIN_SLEEP_TIME_MILLIS);
2371
+ _this._needToFetchStatus = true;
2372
+ _this.completeTransitions_();
2373
+ return;
2374
+ }
2375
+ }
2305
2376
  _this._error = error;
2306
2377
  _this._transition("error" /* ERROR */);
2307
2378
  }
@@ -2316,6 +2387,8 @@ var UploadTask = /** @class */ (function () {
2316
2387
  _this._transition("error" /* ERROR */);
2317
2388
  }
2318
2389
  };
2390
+ this.sleepTime = 0;
2391
+ this.maxSleepTime = this._ref.storage.maxUploadRetryTime;
2319
2392
  this._promise = new Promise(function (resolve, reject) {
2320
2393
  _this._resolve = resolve;
2321
2394
  _this._reject = reject;
@@ -2325,6 +2398,9 @@ var UploadTask = /** @class */ (function () {
2325
2398
  // to the top level with a dummy handler.
2326
2399
  this._promise.then(null, function () { });
2327
2400
  }
2401
+ UploadTask.prototype.isExponentialBackoffExpired = function () {
2402
+ return this.sleepTime > this.maxSleepTime;
2403
+ };
2328
2404
  UploadTask.prototype._makeProgressCallback = function () {
2329
2405
  var _this = this;
2330
2406
  var sizeBefore = this._transferred;
@@ -2334,6 +2410,7 @@ var UploadTask = /** @class */ (function () {
2334
2410
  return blob.size() > 256 * 1024;
2335
2411
  };
2336
2412
  UploadTask.prototype._start = function () {
2413
+ var _this = this;
2337
2414
  if (this._state !== "running" /* RUNNING */) {
2338
2415
  // This can happen if someone pauses us in a resume callback, for example.
2339
2416
  return;
@@ -2355,7 +2432,9 @@ var UploadTask = /** @class */ (function () {
2355
2432
  this._fetchMetadata();
2356
2433
  }
2357
2434
  else {
2358
- this._continueUpload();
2435
+ setTimeout(function () {
2436
+ _this._continueUpload();
2437
+ }, this.sleepTime);
2359
2438
  }
2360
2439
  }
2361
2440
  }
@@ -2436,7 +2515,9 @@ var UploadTask = /** @class */ (function () {
2436
2515
  _this._transition("error" /* ERROR */);
2437
2516
  return;
2438
2517
  }
2439
- var uploadRequest = _this._ref.storage._makeRequest(requestInfo, newTextConnection, authToken, appCheckToken);
2518
+ var uploadRequest = _this._ref.storage._makeRequest(requestInfo, newTextConnection, authToken, appCheckToken,
2519
+ /*retry=*/ false // Upload requests should not be retried as each retry should be preceded by another query request. Which is handled in this file.
2520
+ );
2440
2521
  _this._request = uploadRequest;
2441
2522
  uploadRequest.getPromise().then(function (newStatus) {
2442
2523
  _this._increaseMultiplier();
@@ -2455,7 +2536,7 @@ var UploadTask = /** @class */ (function () {
2455
2536
  UploadTask.prototype._increaseMultiplier = function () {
2456
2537
  var currentSize = RESUMABLE_UPLOAD_CHUNK_SIZE * this._chunkMultiplier;
2457
2538
  // Max chunk size is 32M.
2458
- if (currentSize < 32 * 1024 * 1024) {
2539
+ if (currentSize * 2 < 32 * 1024 * 1024) {
2459
2540
  this._chunkMultiplier *= 2;
2460
2541
  }
2461
2542
  };
@@ -2611,6 +2692,7 @@ var UploadTask = /** @class */ (function () {
2611
2692
  */
2612
2693
  UploadTask.prototype.on = function (type, nextOrObserver, error, completed) {
2613
2694
  var _this = this;
2695
+ // Note: `type` isn't being used. Its type is also incorrect. TaskEvent should not be a string.
2614
2696
  var observer = new Observer(nextOrObserver || undefined, error || undefined, completed || undefined);
2615
2697
  this._addObserver(observer);
2616
2698
  return function () {
@@ -3374,10 +3456,11 @@ var FirebaseStorageImpl = /** @class */ (function () {
3374
3456
  * @param requestInfo - HTTP RequestInfo object
3375
3457
  * @param authToken - Firebase auth token
3376
3458
  */
3377
- FirebaseStorageImpl.prototype._makeRequest = function (requestInfo, requestFactory, authToken, appCheckToken) {
3459
+ FirebaseStorageImpl.prototype._makeRequest = function (requestInfo, requestFactory, authToken, appCheckToken, retry) {
3378
3460
  var _this = this;
3461
+ if (retry === void 0) { retry = true; }
3379
3462
  if (!this._deleted) {
3380
- var request_1 = makeRequest(requestInfo, this._appId, authToken, appCheckToken, requestFactory, this._firebaseVersion);
3463
+ var request_1 = makeRequest(requestInfo, this._appId, authToken, appCheckToken, requestFactory, this._firebaseVersion, retry);
3381
3464
  this._requests.add(request_1);
3382
3465
  // Request removes itself from set when complete.
3383
3466
  request_1.getPromise().then(function () { return _this._requests.delete(request_1); }, function () { return _this._requests.delete(request_1); });
@@ -3407,7 +3490,7 @@ var FirebaseStorageImpl = /** @class */ (function () {
3407
3490
  }());
3408
3491
 
3409
3492
  var name = "@firebase/storage";
3410
- var version = "0.9.10";
3493
+ var version = "0.9.11-20221010203322";
3411
3494
 
3412
3495
  /**
3413
3496
  * @license
@@ -3430,22 +3513,6 @@ var version = "0.9.10";
3430
3513
  */
3431
3514
  var STORAGE_TYPE = 'storage';
3432
3515
 
3433
- /**
3434
- * @license
3435
- * Copyright 2020 Google LLC
3436
- *
3437
- * Licensed under the Apache License, Version 2.0 (the "License");
3438
- * you may not use this file except in compliance with the License.
3439
- * You may obtain a copy of the License at
3440
- *
3441
- * http://www.apache.org/licenses/LICENSE-2.0
3442
- *
3443
- * Unless required by applicable law or agreed to in writing, software
3444
- * distributed under the License is distributed on an "AS IS" BASIS,
3445
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3446
- * See the License for the specific language governing permissions and
3447
- * limitations under the License.
3448
- */
3449
3516
  /**
3450
3517
  * Downloads the data at the object's location. Returns an error if the object
3451
3518
  * is not found.
@@ -3623,11 +3690,9 @@ function getStorage(app$1, bucketUrl) {
3623
3690
  var storageInstance = storageProvider.getImmediate({
3624
3691
  identifier: bucketUrl
3625
3692
  });
3626
- var storageEmulatorHost = util.getDefaultEmulatorHost('storage');
3627
- if (storageEmulatorHost) {
3628
- var _a = storageEmulatorHost.split(':'), host = _a[0], port = _a[1];
3629
- // eslint-disable-next-line no-restricted-globals
3630
- connectStorageEmulator(storageInstance, host, parseInt(port, 10));
3693
+ var emulator = util.getDefaultEmulatorHostnameAndPort('storage');
3694
+ if (emulator) {
3695
+ connectStorageEmulator.apply(void 0, tslib.__spreadArray([storageInstance], emulator));
3631
3696
  }
3632
3697
  return storageInstance;
3633
3698
  }